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_mips64.h"
18
19#include "art_method.h"
20#include "code_generator_utils.h"
21#include "compiled_method.h"
22#include "entrypoints/quick/quick_entrypoints.h"
23#include "entrypoints/quick/quick_entrypoints_enum.h"
24#include "gc/accounting/card_table.h"
25#include "intrinsics.h"
26#include "intrinsics_mips64.h"
27#include "mirror/array-inl.h"
28#include "mirror/class-inl.h"
29#include "offsets.h"
30#include "thread.h"
31#include "utils/assembler.h"
32#include "utils/mips64/assembler_mips64.h"
33#include "utils/stack_checks.h"
34
35namespace art {
36namespace mips64 {
37
38static constexpr int kCurrentMethodStackOffset = 0;
39static constexpr GpuRegister kMethodRegisterArgument = A0;
40
41Location Mips64ReturnLocation(Primitive::Type return_type) {
42  switch (return_type) {
43    case Primitive::kPrimBoolean:
44    case Primitive::kPrimByte:
45    case Primitive::kPrimChar:
46    case Primitive::kPrimShort:
47    case Primitive::kPrimInt:
48    case Primitive::kPrimNot:
49    case Primitive::kPrimLong:
50      return Location::RegisterLocation(V0);
51
52    case Primitive::kPrimFloat:
53    case Primitive::kPrimDouble:
54      return Location::FpuRegisterLocation(F0);
55
56    case Primitive::kPrimVoid:
57      return Location();
58  }
59  UNREACHABLE();
60}
61
62Location InvokeDexCallingConventionVisitorMIPS64::GetReturnLocation(Primitive::Type type) const {
63  return Mips64ReturnLocation(type);
64}
65
66Location InvokeDexCallingConventionVisitorMIPS64::GetMethodLocation() const {
67  return Location::RegisterLocation(kMethodRegisterArgument);
68}
69
70Location InvokeDexCallingConventionVisitorMIPS64::GetNextLocation(Primitive::Type type) {
71  Location next_location;
72  if (type == Primitive::kPrimVoid) {
73    LOG(FATAL) << "Unexpected parameter type " << type;
74  }
75
76  if (Primitive::IsFloatingPointType(type) &&
77      (float_index_ < calling_convention.GetNumberOfFpuRegisters())) {
78    next_location = Location::FpuRegisterLocation(
79        calling_convention.GetFpuRegisterAt(float_index_++));
80    gp_index_++;
81  } else if (!Primitive::IsFloatingPointType(type) &&
82             (gp_index_ < calling_convention.GetNumberOfRegisters())) {
83    next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index_++));
84    float_index_++;
85  } else {
86    size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
87    next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
88                                                 : Location::StackSlot(stack_offset);
89  }
90
91  // Space on the stack is reserved for all arguments.
92  stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
93
94  return next_location;
95}
96
97Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) {
98  return Mips64ReturnLocation(type);
99}
100
101// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
102#define __ down_cast<CodeGeneratorMIPS64*>(codegen)->GetAssembler()->  // NOLINT
103#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, x).Int32Value()
104
105class BoundsCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 {
106 public:
107  explicit BoundsCheckSlowPathMIPS64(HBoundsCheck* instruction) : SlowPathCodeMIPS64(instruction) {}
108
109  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
110    LocationSummary* locations = instruction_->GetLocations();
111    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
112    __ Bind(GetEntryLabel());
113    if (instruction_->CanThrowIntoCatchBlock()) {
114      // Live registers will be restored in the catch block if caught.
115      SaveLiveRegisters(codegen, instruction_->GetLocations());
116    }
117    // We're moving two locations to locations that could overlap, so we need a parallel
118    // move resolver.
119    InvokeRuntimeCallingConvention calling_convention;
120    codegen->EmitParallelMoves(locations->InAt(0),
121                               Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
122                               Primitive::kPrimInt,
123                               locations->InAt(1),
124                               Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
125                               Primitive::kPrimInt);
126    QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
127        ? kQuickThrowStringBounds
128        : kQuickThrowArrayBounds;
129    mips64_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
130    CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
131    CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
132  }
133
134  bool IsFatal() const OVERRIDE { return true; }
135
136  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS64"; }
137
138 private:
139  DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathMIPS64);
140};
141
142class DivZeroCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 {
143 public:
144  explicit DivZeroCheckSlowPathMIPS64(HDivZeroCheck* instruction) : SlowPathCodeMIPS64(instruction) {}
145
146  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
147    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
148    __ Bind(GetEntryLabel());
149    mips64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
150    CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
151  }
152
153  bool IsFatal() const OVERRIDE { return true; }
154
155  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS64"; }
156
157 private:
158  DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS64);
159};
160
161class LoadClassSlowPathMIPS64 : public SlowPathCodeMIPS64 {
162 public:
163  LoadClassSlowPathMIPS64(HLoadClass* cls,
164                          HInstruction* at,
165                          uint32_t dex_pc,
166                          bool do_clinit)
167      : SlowPathCodeMIPS64(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
168    DCHECK(at->IsLoadClass() || at->IsClinitCheck());
169  }
170
171  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
172    LocationSummary* locations = instruction_->GetLocations();
173    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
174
175    __ Bind(GetEntryLabel());
176    SaveLiveRegisters(codegen, locations);
177
178    InvokeRuntimeCallingConvention calling_convention;
179    dex::TypeIndex type_index = cls_->GetTypeIndex();
180    __ LoadConst32(calling_convention.GetRegisterAt(0), type_index.index_);
181    QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
182                                                : kQuickInitializeType;
183    mips64_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
184    if (do_clinit_) {
185      CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
186    } else {
187      CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
188    }
189
190    // Move the class to the desired location.
191    Location out = locations->Out();
192    if (out.IsValid()) {
193      DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
194      Primitive::Type type = instruction_->GetType();
195      mips64_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
196    }
197
198    RestoreLiveRegisters(codegen, locations);
199    // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
200    DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
201    if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
202      DCHECK(out.IsValid());
203      // TODO: Change art_quick_initialize_type/art_quick_initialize_static_storage to
204      // kSaveEverything and use a temporary for the .bss entry address in the fast path,
205      // so that we can avoid another calculation here.
206      DCHECK_NE(out.AsRegister<GpuRegister>(), AT);
207      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
208          mips64_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
209      mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info, AT);
210      __ Sw(out.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
211    }
212    __ Bc(GetExitLabel());
213  }
214
215  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathMIPS64"; }
216
217 private:
218  // The class this slow path will load.
219  HLoadClass* const cls_;
220
221  // The dex PC of `at_`.
222  const uint32_t dex_pc_;
223
224  // Whether to initialize the class.
225  const bool do_clinit_;
226
227  DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS64);
228};
229
230class LoadStringSlowPathMIPS64 : public SlowPathCodeMIPS64 {
231 public:
232  explicit LoadStringSlowPathMIPS64(HLoadString* instruction) : SlowPathCodeMIPS64(instruction) {}
233
234  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
235    LocationSummary* locations = instruction_->GetLocations();
236    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
237    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
238
239    __ Bind(GetEntryLabel());
240    SaveLiveRegisters(codegen, locations);
241
242    InvokeRuntimeCallingConvention calling_convention;
243    HLoadString* load = instruction_->AsLoadString();
244    const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
245    __ LoadConst32(calling_convention.GetRegisterAt(0), string_index.index_);
246    mips64_codegen->InvokeRuntime(kQuickResolveString,
247                                  instruction_,
248                                  instruction_->GetDexPc(),
249                                  this);
250    CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
251    Primitive::Type type = instruction_->GetType();
252    mips64_codegen->MoveLocation(locations->Out(),
253                                 calling_convention.GetReturnLocation(type),
254                                 type);
255
256    RestoreLiveRegisters(codegen, locations);
257
258    // Store the resolved String to the BSS entry.
259    // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary for the
260    // .bss entry address in the fast path, so that we can avoid another calculation here.
261    GpuRegister out = locations->Out().AsRegister<GpuRegister>();
262    DCHECK_NE(out, AT);
263    CodeGeneratorMIPS64::PcRelativePatchInfo* info =
264        mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
265    mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info, AT);
266    __ Sw(out, AT, /* placeholder */ 0x5678);
267
268    __ Bc(GetExitLabel());
269  }
270
271  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS64"; }
272
273 private:
274  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS64);
275};
276
277class NullCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 {
278 public:
279  explicit NullCheckSlowPathMIPS64(HNullCheck* instr) : SlowPathCodeMIPS64(instr) {}
280
281  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
282    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
283    __ Bind(GetEntryLabel());
284    if (instruction_->CanThrowIntoCatchBlock()) {
285      // Live registers will be restored in the catch block if caught.
286      SaveLiveRegisters(codegen, instruction_->GetLocations());
287    }
288    mips64_codegen->InvokeRuntime(kQuickThrowNullPointer,
289                                  instruction_,
290                                  instruction_->GetDexPc(),
291                                  this);
292    CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
293  }
294
295  bool IsFatal() const OVERRIDE { return true; }
296
297  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS64"; }
298
299 private:
300  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathMIPS64);
301};
302
303class SuspendCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 {
304 public:
305  SuspendCheckSlowPathMIPS64(HSuspendCheck* instruction, HBasicBlock* successor)
306      : SlowPathCodeMIPS64(instruction), successor_(successor) {}
307
308  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
309    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
310    __ Bind(GetEntryLabel());
311    mips64_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
312    CheckEntrypointTypes<kQuickTestSuspend, void, void>();
313    if (successor_ == nullptr) {
314      __ Bc(GetReturnLabel());
315    } else {
316      __ Bc(mips64_codegen->GetLabelOf(successor_));
317    }
318  }
319
320  Mips64Label* GetReturnLabel() {
321    DCHECK(successor_ == nullptr);
322    return &return_label_;
323  }
324
325  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS64"; }
326
327 private:
328  // If not null, the block to branch to after the suspend check.
329  HBasicBlock* const successor_;
330
331  // If `successor_` is null, the label to branch to after the suspend check.
332  Mips64Label return_label_;
333
334  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathMIPS64);
335};
336
337class TypeCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 {
338 public:
339  explicit TypeCheckSlowPathMIPS64(HInstruction* instruction, bool is_fatal)
340      : SlowPathCodeMIPS64(instruction), is_fatal_(is_fatal) {}
341
342  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
343    LocationSummary* locations = instruction_->GetLocations();
344
345    uint32_t dex_pc = instruction_->GetDexPc();
346    DCHECK(instruction_->IsCheckCast()
347           || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
348    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
349
350    __ Bind(GetEntryLabel());
351    if (!is_fatal_) {
352      SaveLiveRegisters(codegen, locations);
353    }
354
355    // We're moving two locations to locations that could overlap, so we need a parallel
356    // move resolver.
357    InvokeRuntimeCallingConvention calling_convention;
358    codegen->EmitParallelMoves(locations->InAt(0),
359                               Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
360                               Primitive::kPrimNot,
361                               locations->InAt(1),
362                               Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
363                               Primitive::kPrimNot);
364    if (instruction_->IsInstanceOf()) {
365      mips64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
366      CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
367      Primitive::Type ret_type = instruction_->GetType();
368      Location ret_loc = calling_convention.GetReturnLocation(ret_type);
369      mips64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
370    } else {
371      DCHECK(instruction_->IsCheckCast());
372      mips64_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
373      CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
374    }
375
376    if (!is_fatal_) {
377      RestoreLiveRegisters(codegen, locations);
378      __ Bc(GetExitLabel());
379    }
380  }
381
382  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS64"; }
383
384  bool IsFatal() const OVERRIDE { return is_fatal_; }
385
386 private:
387  const bool is_fatal_;
388
389  DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathMIPS64);
390};
391
392class DeoptimizationSlowPathMIPS64 : public SlowPathCodeMIPS64 {
393 public:
394  explicit DeoptimizationSlowPathMIPS64(HDeoptimize* instruction)
395    : SlowPathCodeMIPS64(instruction) {}
396
397  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
398    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
399    __ Bind(GetEntryLabel());
400      LocationSummary* locations = instruction_->GetLocations();
401    SaveLiveRegisters(codegen, locations);
402    InvokeRuntimeCallingConvention calling_convention;
403    __ LoadConst32(calling_convention.GetRegisterAt(0),
404                   static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
405    mips64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
406    CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
407  }
408
409  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS64"; }
410
411 private:
412  DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS64);
413};
414
415class ArraySetSlowPathMIPS64 : public SlowPathCodeMIPS64 {
416 public:
417  explicit ArraySetSlowPathMIPS64(HInstruction* instruction) : SlowPathCodeMIPS64(instruction) {}
418
419  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
420    LocationSummary* locations = instruction_->GetLocations();
421    __ Bind(GetEntryLabel());
422    SaveLiveRegisters(codegen, locations);
423
424    InvokeRuntimeCallingConvention calling_convention;
425    HParallelMove parallel_move(codegen->GetGraph()->GetArena());
426    parallel_move.AddMove(
427        locations->InAt(0),
428        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
429        Primitive::kPrimNot,
430        nullptr);
431    parallel_move.AddMove(
432        locations->InAt(1),
433        Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
434        Primitive::kPrimInt,
435        nullptr);
436    parallel_move.AddMove(
437        locations->InAt(2),
438        Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
439        Primitive::kPrimNot,
440        nullptr);
441    codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
442
443    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
444    mips64_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
445    CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
446    RestoreLiveRegisters(codegen, locations);
447    __ Bc(GetExitLabel());
448  }
449
450  const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathMIPS64"; }
451
452 private:
453  DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathMIPS64);
454};
455
456// Slow path marking an object reference `ref` during a read
457// barrier. The field `obj.field` in the object `obj` holding this
458// reference does not get updated by this slow path after marking (see
459// ReadBarrierMarkAndUpdateFieldSlowPathMIPS64 below for that).
460//
461// This means that after the execution of this slow path, `ref` will
462// always be up-to-date, but `obj.field` may not; i.e., after the
463// flip, `ref` will be a to-space reference, but `obj.field` will
464// probably still be a from-space reference (unless it gets updated by
465// another thread, or if another thread installed another object
466// reference (different from `ref`) in `obj.field`).
467//
468// If `entrypoint` is a valid location it is assumed to already be
469// holding the entrypoint. The case where the entrypoint is passed in
470// is for the GcRoot read barrier.
471class ReadBarrierMarkSlowPathMIPS64 : public SlowPathCodeMIPS64 {
472 public:
473  ReadBarrierMarkSlowPathMIPS64(HInstruction* instruction,
474                                Location ref,
475                                Location entrypoint = Location::NoLocation())
476      : SlowPathCodeMIPS64(instruction), ref_(ref), entrypoint_(entrypoint) {
477    DCHECK(kEmitCompilerReadBarrier);
478  }
479
480  const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathMIPS"; }
481
482  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
483    LocationSummary* locations = instruction_->GetLocations();
484    GpuRegister ref_reg = ref_.AsRegister<GpuRegister>();
485    DCHECK(locations->CanCall());
486    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
487    DCHECK(instruction_->IsInstanceFieldGet() ||
488           instruction_->IsStaticFieldGet() ||
489           instruction_->IsArrayGet() ||
490           instruction_->IsArraySet() ||
491           instruction_->IsLoadClass() ||
492           instruction_->IsLoadString() ||
493           instruction_->IsInstanceOf() ||
494           instruction_->IsCheckCast() ||
495           (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
496           (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
497        << "Unexpected instruction in read barrier marking slow path: "
498        << instruction_->DebugName();
499
500    __ Bind(GetEntryLabel());
501    // No need to save live registers; it's taken care of by the
502    // entrypoint. Also, there is no need to update the stack mask,
503    // as this runtime call will not trigger a garbage collection.
504    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
505    DCHECK((V0 <= ref_reg && ref_reg <= T2) ||
506           (S2 <= ref_reg && ref_reg <= S7) ||
507           (ref_reg == S8)) << ref_reg;
508    // "Compact" slow path, saving two moves.
509    //
510    // Instead of using the standard runtime calling convention (input
511    // and output in A0 and V0 respectively):
512    //
513    //   A0 <- ref
514    //   V0 <- ReadBarrierMark(A0)
515    //   ref <- V0
516    //
517    // we just use rX (the register containing `ref`) as input and output
518    // of a dedicated entrypoint:
519    //
520    //   rX <- ReadBarrierMarkRegX(rX)
521    //
522    if (entrypoint_.IsValid()) {
523      mips64_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
524      DCHECK_EQ(entrypoint_.AsRegister<GpuRegister>(), T9);
525      __ Jalr(entrypoint_.AsRegister<GpuRegister>());
526      __ Nop();
527    } else {
528      int32_t entry_point_offset =
529          CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kMips64PointerSize>(ref_reg - 1);
530      // This runtime call does not require a stack map.
531      mips64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
532                                                          instruction_,
533                                                          this);
534    }
535    __ Bc(GetExitLabel());
536  }
537
538 private:
539  // The location (register) of the marked object reference.
540  const Location ref_;
541
542  // The location of the entrypoint if already loaded.
543  const Location entrypoint_;
544
545  DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathMIPS64);
546};
547
548// Slow path marking an object reference `ref` during a read barrier,
549// and if needed, atomically updating the field `obj.field` in the
550// object `obj` holding this reference after marking (contrary to
551// ReadBarrierMarkSlowPathMIPS64 above, which never tries to update
552// `obj.field`).
553//
554// This means that after the execution of this slow path, both `ref`
555// and `obj.field` will be up-to-date; i.e., after the flip, both will
556// hold the same to-space reference (unless another thread installed
557// another object reference (different from `ref`) in `obj.field`).
558class ReadBarrierMarkAndUpdateFieldSlowPathMIPS64 : public SlowPathCodeMIPS64 {
559 public:
560  ReadBarrierMarkAndUpdateFieldSlowPathMIPS64(HInstruction* instruction,
561                                              Location ref,
562                                              GpuRegister obj,
563                                              Location field_offset,
564                                              GpuRegister temp1)
565      : SlowPathCodeMIPS64(instruction),
566        ref_(ref),
567        obj_(obj),
568        field_offset_(field_offset),
569        temp1_(temp1) {
570    DCHECK(kEmitCompilerReadBarrier);
571  }
572
573  const char* GetDescription() const OVERRIDE {
574    return "ReadBarrierMarkAndUpdateFieldSlowPathMIPS64";
575  }
576
577  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
578    LocationSummary* locations = instruction_->GetLocations();
579    GpuRegister ref_reg = ref_.AsRegister<GpuRegister>();
580    DCHECK(locations->CanCall());
581    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
582    // This slow path is only used by the UnsafeCASObject intrinsic.
583    DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
584        << "Unexpected instruction in read barrier marking and field updating slow path: "
585        << instruction_->DebugName();
586    DCHECK(instruction_->GetLocations()->Intrinsified());
587    DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
588    DCHECK(field_offset_.IsRegister()) << field_offset_;
589
590    __ Bind(GetEntryLabel());
591
592    // Save the old reference.
593    // Note that we cannot use AT or TMP to save the old reference, as those
594    // are used by the code that follows, but we need the old reference after
595    // the call to the ReadBarrierMarkRegX entry point.
596    DCHECK_NE(temp1_, AT);
597    DCHECK_NE(temp1_, TMP);
598    __ Move(temp1_, ref_reg);
599
600    // No need to save live registers; it's taken care of by the
601    // entrypoint. Also, there is no need to update the stack mask,
602    // as this runtime call will not trigger a garbage collection.
603    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
604    DCHECK((V0 <= ref_reg && ref_reg <= T2) ||
605           (S2 <= ref_reg && ref_reg <= S7) ||
606           (ref_reg == S8)) << ref_reg;
607    // "Compact" slow path, saving two moves.
608    //
609    // Instead of using the standard runtime calling convention (input
610    // and output in A0 and V0 respectively):
611    //
612    //   A0 <- ref
613    //   V0 <- ReadBarrierMark(A0)
614    //   ref <- V0
615    //
616    // we just use rX (the register containing `ref`) as input and output
617    // of a dedicated entrypoint:
618    //
619    //   rX <- ReadBarrierMarkRegX(rX)
620    //
621    int32_t entry_point_offset =
622        CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kMips64PointerSize>(ref_reg - 1);
623    // This runtime call does not require a stack map.
624    mips64_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
625                                                        instruction_,
626                                                        this);
627
628    // If the new reference is different from the old reference,
629    // update the field in the holder (`*(obj_ + field_offset_)`).
630    //
631    // Note that this field could also hold a different object, if
632    // another thread had concurrently changed it. In that case, the
633    // the compare-and-set (CAS) loop below would abort, leaving the
634    // field as-is.
635    Mips64Label done;
636    __ Beqc(temp1_, ref_reg, &done);
637
638    // Update the the holder's field atomically.  This may fail if
639    // mutator updates before us, but it's OK.  This is achieved
640    // using a strong compare-and-set (CAS) operation with relaxed
641    // memory synchronization ordering, where the expected value is
642    // the old reference and the desired value is the new reference.
643
644    // Convenience aliases.
645    GpuRegister base = obj_;
646    GpuRegister offset = field_offset_.AsRegister<GpuRegister>();
647    GpuRegister expected = temp1_;
648    GpuRegister value = ref_reg;
649    GpuRegister tmp_ptr = TMP;      // Pointer to actual memory.
650    GpuRegister tmp = AT;           // Value in memory.
651
652    __ Daddu(tmp_ptr, base, offset);
653
654    if (kPoisonHeapReferences) {
655      __ PoisonHeapReference(expected);
656      // Do not poison `value` if it is the same register as
657      // `expected`, which has just been poisoned.
658      if (value != expected) {
659        __ PoisonHeapReference(value);
660      }
661    }
662
663    // do {
664    //   tmp = [r_ptr] - expected;
665    // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
666
667    Mips64Label loop_head, exit_loop;
668    __ Bind(&loop_head);
669    __ Ll(tmp, tmp_ptr);
670    // The LL instruction sign-extends the 32-bit value, but
671    // 32-bit references must be zero-extended. Zero-extend `tmp`.
672    __ Dext(tmp, tmp, 0, 32);
673    __ Bnec(tmp, expected, &exit_loop);
674    __ Move(tmp, value);
675    __ Sc(tmp, tmp_ptr);
676    __ Beqzc(tmp, &loop_head);
677    __ Bind(&exit_loop);
678
679    if (kPoisonHeapReferences) {
680      __ UnpoisonHeapReference(expected);
681      // Do not unpoison `value` if it is the same register as
682      // `expected`, which has just been unpoisoned.
683      if (value != expected) {
684        __ UnpoisonHeapReference(value);
685      }
686    }
687
688    __ Bind(&done);
689    __ Bc(GetExitLabel());
690  }
691
692 private:
693  // The location (register) of the marked object reference.
694  const Location ref_;
695  // The register containing the object holding the marked object reference field.
696  const GpuRegister obj_;
697  // The location of the offset of the marked reference field within `obj_`.
698  Location field_offset_;
699
700  const GpuRegister temp1_;
701
702  DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathMIPS64);
703};
704
705// Slow path generating a read barrier for a heap reference.
706class ReadBarrierForHeapReferenceSlowPathMIPS64 : public SlowPathCodeMIPS64 {
707 public:
708  ReadBarrierForHeapReferenceSlowPathMIPS64(HInstruction* instruction,
709                                            Location out,
710                                            Location ref,
711                                            Location obj,
712                                            uint32_t offset,
713                                            Location index)
714      : SlowPathCodeMIPS64(instruction),
715        out_(out),
716        ref_(ref),
717        obj_(obj),
718        offset_(offset),
719        index_(index) {
720    DCHECK(kEmitCompilerReadBarrier);
721    // If `obj` is equal to `out` or `ref`, it means the initial object
722    // has been overwritten by (or after) the heap object reference load
723    // to be instrumented, e.g.:
724    //
725    //   __ LoadFromOffset(kLoadWord, out, out, offset);
726    //   codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
727    //
728    // In that case, we have lost the information about the original
729    // object, and the emitted read barrier cannot work properly.
730    DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
731    DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
732  }
733
734  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
735    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
736    LocationSummary* locations = instruction_->GetLocations();
737    Primitive::Type type = Primitive::kPrimNot;
738    GpuRegister reg_out = out_.AsRegister<GpuRegister>();
739    DCHECK(locations->CanCall());
740    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
741    DCHECK(instruction_->IsInstanceFieldGet() ||
742           instruction_->IsStaticFieldGet() ||
743           instruction_->IsArrayGet() ||
744           instruction_->IsInstanceOf() ||
745           instruction_->IsCheckCast() ||
746           (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
747        << "Unexpected instruction in read barrier for heap reference slow path: "
748        << instruction_->DebugName();
749
750    __ Bind(GetEntryLabel());
751    SaveLiveRegisters(codegen, locations);
752
753    // We may have to change the index's value, but as `index_` is a
754    // constant member (like other "inputs" of this slow path),
755    // introduce a copy of it, `index`.
756    Location index = index_;
757    if (index_.IsValid()) {
758      // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
759      if (instruction_->IsArrayGet()) {
760        // Compute the actual memory offset and store it in `index`.
761        GpuRegister index_reg = index_.AsRegister<GpuRegister>();
762        DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
763        if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
764          // We are about to change the value of `index_reg` (see the
765          // calls to art::mips64::Mips64Assembler::Sll and
766          // art::mips64::MipsAssembler::Addiu32 below), but it has
767          // not been saved by the previous call to
768          // art::SlowPathCode::SaveLiveRegisters, as it is a
769          // callee-save register --
770          // art::SlowPathCode::SaveLiveRegisters does not consider
771          // callee-save registers, as it has been designed with the
772          // assumption that callee-save registers are supposed to be
773          // handled by the called function.  So, as a callee-save
774          // register, `index_reg` _would_ eventually be saved onto
775          // the stack, but it would be too late: we would have
776          // changed its value earlier.  Therefore, we manually save
777          // it here into another freely available register,
778          // `free_reg`, chosen of course among the caller-save
779          // registers (as a callee-save `free_reg` register would
780          // exhibit the same problem).
781          //
782          // Note we could have requested a temporary register from
783          // the register allocator instead; but we prefer not to, as
784          // this is a slow path, and we know we can find a
785          // caller-save register that is available.
786          GpuRegister free_reg = FindAvailableCallerSaveRegister(codegen);
787          __ Move(free_reg, index_reg);
788          index_reg = free_reg;
789          index = Location::RegisterLocation(index_reg);
790        } else {
791          // The initial register stored in `index_` has already been
792          // saved in the call to art::SlowPathCode::SaveLiveRegisters
793          // (as it is not a callee-save register), so we can freely
794          // use it.
795        }
796        // Shifting the index value contained in `index_reg` by the scale
797        // factor (2) cannot overflow in practice, as the runtime is
798        // unable to allocate object arrays with a size larger than
799        // 2^26 - 1 (that is, 2^28 - 4 bytes).
800        __ Sll(index_reg, index_reg, TIMES_4);
801        static_assert(
802            sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
803            "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
804        __ Addiu32(index_reg, index_reg, offset_);
805      } else {
806        // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
807        // intrinsics, `index_` is not shifted by a scale factor of 2
808        // (as in the case of ArrayGet), as it is actually an offset
809        // to an object field within an object.
810        DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
811        DCHECK(instruction_->GetLocations()->Intrinsified());
812        DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
813               (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
814            << instruction_->AsInvoke()->GetIntrinsic();
815        DCHECK_EQ(offset_, 0U);
816        DCHECK(index_.IsRegister());
817      }
818    }
819
820    // We're moving two or three locations to locations that could
821    // overlap, so we need a parallel move resolver.
822    InvokeRuntimeCallingConvention calling_convention;
823    HParallelMove parallel_move(codegen->GetGraph()->GetArena());
824    parallel_move.AddMove(ref_,
825                          Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
826                          Primitive::kPrimNot,
827                          nullptr);
828    parallel_move.AddMove(obj_,
829                          Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
830                          Primitive::kPrimNot,
831                          nullptr);
832    if (index.IsValid()) {
833      parallel_move.AddMove(index,
834                            Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
835                            Primitive::kPrimInt,
836                            nullptr);
837      codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
838    } else {
839      codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
840      __ LoadConst32(calling_convention.GetRegisterAt(2), offset_);
841    }
842    mips64_codegen->InvokeRuntime(kQuickReadBarrierSlow,
843                                  instruction_,
844                                  instruction_->GetDexPc(),
845                                  this);
846    CheckEntrypointTypes<
847        kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
848    mips64_codegen->MoveLocation(out_, calling_convention.GetReturnLocation(type), type);
849
850    RestoreLiveRegisters(codegen, locations);
851    __ Bc(GetExitLabel());
852  }
853
854  const char* GetDescription() const OVERRIDE {
855    return "ReadBarrierForHeapReferenceSlowPathMIPS64";
856  }
857
858 private:
859  GpuRegister FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
860    size_t ref = static_cast<int>(ref_.AsRegister<GpuRegister>());
861    size_t obj = static_cast<int>(obj_.AsRegister<GpuRegister>());
862    for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
863      if (i != ref &&
864          i != obj &&
865          !codegen->IsCoreCalleeSaveRegister(i) &&
866          !codegen->IsBlockedCoreRegister(i)) {
867        return static_cast<GpuRegister>(i);
868      }
869    }
870    // We shall never fail to find a free caller-save register, as
871    // there are more than two core caller-save registers on MIPS64
872    // (meaning it is possible to find one which is different from
873    // `ref` and `obj`).
874    DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
875    LOG(FATAL) << "Could not find a free caller-save register";
876    UNREACHABLE();
877  }
878
879  const Location out_;
880  const Location ref_;
881  const Location obj_;
882  const uint32_t offset_;
883  // An additional location containing an index to an array.
884  // Only used for HArrayGet and the UnsafeGetObject &
885  // UnsafeGetObjectVolatile intrinsics.
886  const Location index_;
887
888  DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathMIPS64);
889};
890
891// Slow path generating a read barrier for a GC root.
892class ReadBarrierForRootSlowPathMIPS64 : public SlowPathCodeMIPS64 {
893 public:
894  ReadBarrierForRootSlowPathMIPS64(HInstruction* instruction, Location out, Location root)
895      : SlowPathCodeMIPS64(instruction), out_(out), root_(root) {
896    DCHECK(kEmitCompilerReadBarrier);
897  }
898
899  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
900    LocationSummary* locations = instruction_->GetLocations();
901    Primitive::Type type = Primitive::kPrimNot;
902    GpuRegister reg_out = out_.AsRegister<GpuRegister>();
903    DCHECK(locations->CanCall());
904    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
905    DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
906        << "Unexpected instruction in read barrier for GC root slow path: "
907        << instruction_->DebugName();
908
909    __ Bind(GetEntryLabel());
910    SaveLiveRegisters(codegen, locations);
911
912    InvokeRuntimeCallingConvention calling_convention;
913    CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
914    mips64_codegen->MoveLocation(Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
915                                 root_,
916                                 Primitive::kPrimNot);
917    mips64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
918                                  instruction_,
919                                  instruction_->GetDexPc(),
920                                  this);
921    CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
922    mips64_codegen->MoveLocation(out_, calling_convention.GetReturnLocation(type), type);
923
924    RestoreLiveRegisters(codegen, locations);
925    __ Bc(GetExitLabel());
926  }
927
928  const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathMIPS64"; }
929
930 private:
931  const Location out_;
932  const Location root_;
933
934  DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathMIPS64);
935};
936
937CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph,
938                                         const Mips64InstructionSetFeatures& isa_features,
939                                         const CompilerOptions& compiler_options,
940                                         OptimizingCompilerStats* stats)
941    : CodeGenerator(graph,
942                    kNumberOfGpuRegisters,
943                    kNumberOfFpuRegisters,
944                    /* number_of_register_pairs */ 0,
945                    ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
946                                        arraysize(kCoreCalleeSaves)),
947                    ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
948                                        arraysize(kFpuCalleeSaves)),
949                    compiler_options,
950                    stats),
951      block_labels_(nullptr),
952      location_builder_(graph, this),
953      instruction_visitor_(graph, this),
954      move_resolver_(graph->GetArena(), this),
955      assembler_(graph->GetArena()),
956      isa_features_(isa_features),
957      uint32_literals_(std::less<uint32_t>(),
958                       graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
959      uint64_literals_(std::less<uint64_t>(),
960                       graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
961      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
962      boot_image_string_patches_(StringReferenceValueComparator(),
963                                 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
964      pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
965      boot_image_type_patches_(TypeReferenceValueComparator(),
966                               graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
967      pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
968      type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
969      jit_string_patches_(StringReferenceValueComparator(),
970                          graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
971      jit_class_patches_(TypeReferenceValueComparator(),
972                         graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
973  // Save RA (containing the return address) to mimic Quick.
974  AddAllocatedRegister(Location::RegisterLocation(RA));
975}
976
977#undef __
978// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
979#define __ down_cast<Mips64Assembler*>(GetAssembler())->  // NOLINT
980#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64PointerSize, x).Int32Value()
981
982void CodeGeneratorMIPS64::Finalize(CodeAllocator* allocator) {
983  // Ensure that we fix up branches.
984  __ FinalizeCode();
985
986  // Adjust native pc offsets in stack maps.
987  for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
988    uint32_t old_position =
989        stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kMips64);
990    uint32_t new_position = __ GetAdjustedPosition(old_position);
991    DCHECK_GE(new_position, old_position);
992    stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
993  }
994
995  // Adjust pc offsets for the disassembly information.
996  if (disasm_info_ != nullptr) {
997    GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
998    frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
999    frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
1000    for (auto& it : *disasm_info_->GetInstructionIntervals()) {
1001      it.second.start = __ GetAdjustedPosition(it.second.start);
1002      it.second.end = __ GetAdjustedPosition(it.second.end);
1003    }
1004    for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
1005      it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
1006      it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
1007    }
1008  }
1009
1010  CodeGenerator::Finalize(allocator);
1011}
1012
1013Mips64Assembler* ParallelMoveResolverMIPS64::GetAssembler() const {
1014  return codegen_->GetAssembler();
1015}
1016
1017void ParallelMoveResolverMIPS64::EmitMove(size_t index) {
1018  MoveOperands* move = moves_[index];
1019  codegen_->MoveLocation(move->GetDestination(), move->GetSource(), move->GetType());
1020}
1021
1022void ParallelMoveResolverMIPS64::EmitSwap(size_t index) {
1023  MoveOperands* move = moves_[index];
1024  codegen_->SwapLocations(move->GetDestination(), move->GetSource(), move->GetType());
1025}
1026
1027void ParallelMoveResolverMIPS64::RestoreScratch(int reg) {
1028  // Pop reg
1029  __ Ld(GpuRegister(reg), SP, 0);
1030  __ DecreaseFrameSize(kMips64DoublewordSize);
1031}
1032
1033void ParallelMoveResolverMIPS64::SpillScratch(int reg) {
1034  // Push reg
1035  __ IncreaseFrameSize(kMips64DoublewordSize);
1036  __ Sd(GpuRegister(reg), SP, 0);
1037}
1038
1039void ParallelMoveResolverMIPS64::Exchange(int index1, int index2, bool double_slot) {
1040  LoadOperandType load_type = double_slot ? kLoadDoubleword : kLoadWord;
1041  StoreOperandType store_type = double_slot ? kStoreDoubleword : kStoreWord;
1042  // Allocate a scratch register other than TMP, if available.
1043  // Else, spill V0 (arbitrary choice) and use it as a scratch register (it will be
1044  // automatically unspilled when the scratch scope object is destroyed).
1045  ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters());
1046  // If V0 spills onto the stack, SP-relative offsets need to be adjusted.
1047  int stack_offset = ensure_scratch.IsSpilled() ? kMips64DoublewordSize : 0;
1048  __ LoadFromOffset(load_type,
1049                    GpuRegister(ensure_scratch.GetRegister()),
1050                    SP,
1051                    index1 + stack_offset);
1052  __ LoadFromOffset(load_type,
1053                    TMP,
1054                    SP,
1055                    index2 + stack_offset);
1056  __ StoreToOffset(store_type,
1057                   GpuRegister(ensure_scratch.GetRegister()),
1058                   SP,
1059                   index2 + stack_offset);
1060  __ StoreToOffset(store_type, TMP, SP, index1 + stack_offset);
1061}
1062
1063static dwarf::Reg DWARFReg(GpuRegister reg) {
1064  return dwarf::Reg::Mips64Core(static_cast<int>(reg));
1065}
1066
1067static dwarf::Reg DWARFReg(FpuRegister reg) {
1068  return dwarf::Reg::Mips64Fp(static_cast<int>(reg));
1069}
1070
1071void CodeGeneratorMIPS64::GenerateFrameEntry() {
1072  __ Bind(&frame_entry_label_);
1073
1074  bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kMips64) || !IsLeafMethod();
1075
1076  if (do_overflow_check) {
1077    __ LoadFromOffset(kLoadWord,
1078                      ZERO,
1079                      SP,
1080                      -static_cast<int32_t>(GetStackOverflowReservedBytes(kMips64)));
1081    RecordPcInfo(nullptr, 0);
1082  }
1083
1084  if (HasEmptyFrame()) {
1085    return;
1086  }
1087
1088  // Make sure the frame size isn't unreasonably large.
1089  if (GetFrameSize() > GetStackOverflowReservedBytes(kMips64)) {
1090    LOG(FATAL) << "Stack frame larger than " << GetStackOverflowReservedBytes(kMips64) << " bytes";
1091  }
1092
1093  // Spill callee-saved registers.
1094
1095  uint32_t ofs = GetFrameSize();
1096  __ IncreaseFrameSize(ofs);
1097
1098  for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
1099    GpuRegister reg = kCoreCalleeSaves[i];
1100    if (allocated_registers_.ContainsCoreRegister(reg)) {
1101      ofs -= kMips64DoublewordSize;
1102      __ StoreToOffset(kStoreDoubleword, reg, SP, ofs);
1103      __ cfi().RelOffset(DWARFReg(reg), ofs);
1104    }
1105  }
1106
1107  for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
1108    FpuRegister reg = kFpuCalleeSaves[i];
1109    if (allocated_registers_.ContainsFloatingPointRegister(reg)) {
1110      ofs -= kMips64DoublewordSize;
1111      __ StoreFpuToOffset(kStoreDoubleword, reg, SP, ofs);
1112      __ cfi().RelOffset(DWARFReg(reg), ofs);
1113    }
1114  }
1115
1116  // Save the current method if we need it. Note that we do not
1117  // do this in HCurrentMethod, as the instruction might have been removed
1118  // in the SSA graph.
1119  if (RequiresCurrentMethod()) {
1120    __ StoreToOffset(kStoreDoubleword, kMethodRegisterArgument, SP, kCurrentMethodStackOffset);
1121  }
1122
1123  if (GetGraph()->HasShouldDeoptimizeFlag()) {
1124    // Initialize should_deoptimize flag to 0.
1125    __ StoreToOffset(kStoreWord, ZERO, SP, GetStackOffsetOfShouldDeoptimizeFlag());
1126  }
1127}
1128
1129void CodeGeneratorMIPS64::GenerateFrameExit() {
1130  __ cfi().RememberState();
1131
1132  if (!HasEmptyFrame()) {
1133    // Restore callee-saved registers.
1134
1135    // For better instruction scheduling restore RA before other registers.
1136    uint32_t ofs = GetFrameSize();
1137    for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
1138      GpuRegister reg = kCoreCalleeSaves[i];
1139      if (allocated_registers_.ContainsCoreRegister(reg)) {
1140        ofs -= kMips64DoublewordSize;
1141        __ LoadFromOffset(kLoadDoubleword, reg, SP, ofs);
1142        __ cfi().Restore(DWARFReg(reg));
1143      }
1144    }
1145
1146    for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
1147      FpuRegister reg = kFpuCalleeSaves[i];
1148      if (allocated_registers_.ContainsFloatingPointRegister(reg)) {
1149        ofs -= kMips64DoublewordSize;
1150        __ LoadFpuFromOffset(kLoadDoubleword, reg, SP, ofs);
1151        __ cfi().Restore(DWARFReg(reg));
1152      }
1153    }
1154
1155    __ DecreaseFrameSize(GetFrameSize());
1156  }
1157
1158  __ Jic(RA, 0);
1159
1160  __ cfi().RestoreState();
1161  __ cfi().DefCFAOffset(GetFrameSize());
1162}
1163
1164void CodeGeneratorMIPS64::Bind(HBasicBlock* block) {
1165  __ Bind(GetLabelOf(block));
1166}
1167
1168void CodeGeneratorMIPS64::MoveLocation(Location destination,
1169                                       Location source,
1170                                       Primitive::Type dst_type) {
1171  if (source.Equals(destination)) {
1172    return;
1173  }
1174
1175  // A valid move can always be inferred from the destination and source
1176  // locations. When moving from and to a register, the argument type can be
1177  // used to generate 32bit instead of 64bit moves.
1178  bool unspecified_type = (dst_type == Primitive::kPrimVoid);
1179  DCHECK_EQ(unspecified_type, false);
1180
1181  if (destination.IsRegister() || destination.IsFpuRegister()) {
1182    if (unspecified_type) {
1183      HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
1184      if (source.IsStackSlot() ||
1185          (src_cst != nullptr && (src_cst->IsIntConstant()
1186                                  || src_cst->IsFloatConstant()
1187                                  || src_cst->IsNullConstant()))) {
1188        // For stack slots and 32bit constants, a 64bit type is appropriate.
1189        dst_type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
1190      } else {
1191        // If the source is a double stack slot or a 64bit constant, a 64bit
1192        // type is appropriate. Else the source is a register, and since the
1193        // type has not been specified, we chose a 64bit type to force a 64bit
1194        // move.
1195        dst_type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
1196      }
1197    }
1198    DCHECK((destination.IsFpuRegister() && Primitive::IsFloatingPointType(dst_type)) ||
1199           (destination.IsRegister() && !Primitive::IsFloatingPointType(dst_type)));
1200    if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
1201      // Move to GPR/FPR from stack
1202      LoadOperandType load_type = source.IsStackSlot() ? kLoadWord : kLoadDoubleword;
1203      if (Primitive::IsFloatingPointType(dst_type)) {
1204        __ LoadFpuFromOffset(load_type,
1205                             destination.AsFpuRegister<FpuRegister>(),
1206                             SP,
1207                             source.GetStackIndex());
1208      } else {
1209        // TODO: use load_type = kLoadUnsignedWord when type == Primitive::kPrimNot.
1210        __ LoadFromOffset(load_type,
1211                          destination.AsRegister<GpuRegister>(),
1212                          SP,
1213                          source.GetStackIndex());
1214      }
1215    } else if (source.IsConstant()) {
1216      // Move to GPR/FPR from constant
1217      GpuRegister gpr = AT;
1218      if (!Primitive::IsFloatingPointType(dst_type)) {
1219        gpr = destination.AsRegister<GpuRegister>();
1220      }
1221      if (dst_type == Primitive::kPrimInt || dst_type == Primitive::kPrimFloat) {
1222        int32_t value = GetInt32ValueOf(source.GetConstant()->AsConstant());
1223        if (Primitive::IsFloatingPointType(dst_type) && value == 0) {
1224          gpr = ZERO;
1225        } else {
1226          __ LoadConst32(gpr, value);
1227        }
1228      } else {
1229        int64_t value = GetInt64ValueOf(source.GetConstant()->AsConstant());
1230        if (Primitive::IsFloatingPointType(dst_type) && value == 0) {
1231          gpr = ZERO;
1232        } else {
1233          __ LoadConst64(gpr, value);
1234        }
1235      }
1236      if (dst_type == Primitive::kPrimFloat) {
1237        __ Mtc1(gpr, destination.AsFpuRegister<FpuRegister>());
1238      } else if (dst_type == Primitive::kPrimDouble) {
1239        __ Dmtc1(gpr, destination.AsFpuRegister<FpuRegister>());
1240      }
1241    } else if (source.IsRegister()) {
1242      if (destination.IsRegister()) {
1243        // Move to GPR from GPR
1244        __ Move(destination.AsRegister<GpuRegister>(), source.AsRegister<GpuRegister>());
1245      } else {
1246        DCHECK(destination.IsFpuRegister());
1247        if (Primitive::Is64BitType(dst_type)) {
1248          __ Dmtc1(source.AsRegister<GpuRegister>(), destination.AsFpuRegister<FpuRegister>());
1249        } else {
1250          __ Mtc1(source.AsRegister<GpuRegister>(), destination.AsFpuRegister<FpuRegister>());
1251        }
1252      }
1253    } else if (source.IsFpuRegister()) {
1254      if (destination.IsFpuRegister()) {
1255        // Move to FPR from FPR
1256        if (dst_type == Primitive::kPrimFloat) {
1257          __ MovS(destination.AsFpuRegister<FpuRegister>(), source.AsFpuRegister<FpuRegister>());
1258        } else {
1259          DCHECK_EQ(dst_type, Primitive::kPrimDouble);
1260          __ MovD(destination.AsFpuRegister<FpuRegister>(), source.AsFpuRegister<FpuRegister>());
1261        }
1262      } else {
1263        DCHECK(destination.IsRegister());
1264        if (Primitive::Is64BitType(dst_type)) {
1265          __ Dmfc1(destination.AsRegister<GpuRegister>(), source.AsFpuRegister<FpuRegister>());
1266        } else {
1267          __ Mfc1(destination.AsRegister<GpuRegister>(), source.AsFpuRegister<FpuRegister>());
1268        }
1269      }
1270    }
1271  } else {  // The destination is not a register. It must be a stack slot.
1272    DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
1273    if (source.IsRegister() || source.IsFpuRegister()) {
1274      if (unspecified_type) {
1275        if (source.IsRegister()) {
1276          dst_type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
1277        } else {
1278          dst_type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
1279        }
1280      }
1281      DCHECK((destination.IsDoubleStackSlot() == Primitive::Is64BitType(dst_type)) &&
1282             (source.IsFpuRegister() == Primitive::IsFloatingPointType(dst_type)));
1283      // Move to stack from GPR/FPR
1284      StoreOperandType store_type = destination.IsStackSlot() ? kStoreWord : kStoreDoubleword;
1285      if (source.IsRegister()) {
1286        __ StoreToOffset(store_type,
1287                         source.AsRegister<GpuRegister>(),
1288                         SP,
1289                         destination.GetStackIndex());
1290      } else {
1291        __ StoreFpuToOffset(store_type,
1292                            source.AsFpuRegister<FpuRegister>(),
1293                            SP,
1294                            destination.GetStackIndex());
1295      }
1296    } else if (source.IsConstant()) {
1297      // Move to stack from constant
1298      HConstant* src_cst = source.GetConstant();
1299      StoreOperandType store_type = destination.IsStackSlot() ? kStoreWord : kStoreDoubleword;
1300      GpuRegister gpr = ZERO;
1301      if (destination.IsStackSlot()) {
1302        int32_t value = GetInt32ValueOf(src_cst->AsConstant());
1303        if (value != 0) {
1304          gpr = TMP;
1305          __ LoadConst32(gpr, value);
1306        }
1307      } else {
1308        DCHECK(destination.IsDoubleStackSlot());
1309        int64_t value = GetInt64ValueOf(src_cst->AsConstant());
1310        if (value != 0) {
1311          gpr = TMP;
1312          __ LoadConst64(gpr, value);
1313        }
1314      }
1315      __ StoreToOffset(store_type, gpr, SP, destination.GetStackIndex());
1316    } else {
1317      DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
1318      DCHECK_EQ(source.IsDoubleStackSlot(), destination.IsDoubleStackSlot());
1319      // Move to stack from stack
1320      if (destination.IsStackSlot()) {
1321        __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
1322        __ StoreToOffset(kStoreWord, TMP, SP, destination.GetStackIndex());
1323      } else {
1324        __ LoadFromOffset(kLoadDoubleword, TMP, SP, source.GetStackIndex());
1325        __ StoreToOffset(kStoreDoubleword, TMP, SP, destination.GetStackIndex());
1326      }
1327    }
1328  }
1329}
1330
1331void CodeGeneratorMIPS64::SwapLocations(Location loc1, Location loc2, Primitive::Type type) {
1332  DCHECK(!loc1.IsConstant());
1333  DCHECK(!loc2.IsConstant());
1334
1335  if (loc1.Equals(loc2)) {
1336    return;
1337  }
1338
1339  bool is_slot1 = loc1.IsStackSlot() || loc1.IsDoubleStackSlot();
1340  bool is_slot2 = loc2.IsStackSlot() || loc2.IsDoubleStackSlot();
1341  bool is_fp_reg1 = loc1.IsFpuRegister();
1342  bool is_fp_reg2 = loc2.IsFpuRegister();
1343
1344  if (loc2.IsRegister() && loc1.IsRegister()) {
1345    // Swap 2 GPRs
1346    GpuRegister r1 = loc1.AsRegister<GpuRegister>();
1347    GpuRegister r2 = loc2.AsRegister<GpuRegister>();
1348    __ Move(TMP, r2);
1349    __ Move(r2, r1);
1350    __ Move(r1, TMP);
1351  } else if (is_fp_reg2 && is_fp_reg1) {
1352    // Swap 2 FPRs
1353    FpuRegister r1 = loc1.AsFpuRegister<FpuRegister>();
1354    FpuRegister r2 = loc2.AsFpuRegister<FpuRegister>();
1355    if (type == Primitive::kPrimFloat) {
1356      __ MovS(FTMP, r1);
1357      __ MovS(r1, r2);
1358      __ MovS(r2, FTMP);
1359    } else {
1360      DCHECK_EQ(type, Primitive::kPrimDouble);
1361      __ MovD(FTMP, r1);
1362      __ MovD(r1, r2);
1363      __ MovD(r2, FTMP);
1364    }
1365  } else if (is_slot1 != is_slot2) {
1366    // Swap GPR/FPR and stack slot
1367    Location reg_loc = is_slot1 ? loc2 : loc1;
1368    Location mem_loc = is_slot1 ? loc1 : loc2;
1369    LoadOperandType load_type = mem_loc.IsStackSlot() ? kLoadWord : kLoadDoubleword;
1370    StoreOperandType store_type = mem_loc.IsStackSlot() ? kStoreWord : kStoreDoubleword;
1371    // TODO: use load_type = kLoadUnsignedWord when type == Primitive::kPrimNot.
1372    __ LoadFromOffset(load_type, TMP, SP, mem_loc.GetStackIndex());
1373    if (reg_loc.IsFpuRegister()) {
1374      __ StoreFpuToOffset(store_type,
1375                          reg_loc.AsFpuRegister<FpuRegister>(),
1376                          SP,
1377                          mem_loc.GetStackIndex());
1378      if (mem_loc.IsStackSlot()) {
1379        __ Mtc1(TMP, reg_loc.AsFpuRegister<FpuRegister>());
1380      } else {
1381        DCHECK(mem_loc.IsDoubleStackSlot());
1382        __ Dmtc1(TMP, reg_loc.AsFpuRegister<FpuRegister>());
1383      }
1384    } else {
1385      __ StoreToOffset(store_type, reg_loc.AsRegister<GpuRegister>(), SP, mem_loc.GetStackIndex());
1386      __ Move(reg_loc.AsRegister<GpuRegister>(), TMP);
1387    }
1388  } else if (is_slot1 && is_slot2) {
1389    move_resolver_.Exchange(loc1.GetStackIndex(),
1390                            loc2.GetStackIndex(),
1391                            loc1.IsDoubleStackSlot());
1392  } else {
1393    LOG(FATAL) << "Unimplemented swap between locations " << loc1 << " and " << loc2;
1394  }
1395}
1396
1397void CodeGeneratorMIPS64::MoveConstant(Location location, int32_t value) {
1398  DCHECK(location.IsRegister());
1399  __ LoadConst32(location.AsRegister<GpuRegister>(), value);
1400}
1401
1402void CodeGeneratorMIPS64::AddLocationAsTemp(Location location, LocationSummary* locations) {
1403  if (location.IsRegister()) {
1404    locations->AddTemp(location);
1405  } else {
1406    UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1407  }
1408}
1409
1410void CodeGeneratorMIPS64::MarkGCCard(GpuRegister object,
1411                                     GpuRegister value,
1412                                     bool value_can_be_null) {
1413  Mips64Label done;
1414  GpuRegister card = AT;
1415  GpuRegister temp = TMP;
1416  if (value_can_be_null) {
1417    __ Beqzc(value, &done);
1418  }
1419  __ LoadFromOffset(kLoadDoubleword,
1420                    card,
1421                    TR,
1422                    Thread::CardTableOffset<kMips64PointerSize>().Int32Value());
1423  __ Dsrl(temp, object, gc::accounting::CardTable::kCardShift);
1424  __ Daddu(temp, card, temp);
1425  __ Sb(card, temp, 0);
1426  if (value_can_be_null) {
1427    __ Bind(&done);
1428  }
1429}
1430
1431template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
1432inline void CodeGeneratorMIPS64::EmitPcRelativeLinkerPatches(
1433    const ArenaDeque<PcRelativePatchInfo>& infos,
1434    ArenaVector<LinkerPatch>* linker_patches) {
1435  for (const PcRelativePatchInfo& info : infos) {
1436    const DexFile& dex_file = info.target_dex_file;
1437    size_t offset_or_index = info.offset_or_index;
1438    DCHECK(info.pc_rel_label.IsBound());
1439    uint32_t pc_rel_offset = __ GetLabelLocation(&info.pc_rel_label);
1440    linker_patches->push_back(Factory(pc_rel_offset, &dex_file, pc_rel_offset, offset_or_index));
1441  }
1442}
1443
1444void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
1445  DCHECK(linker_patches->empty());
1446  size_t size =
1447      pc_relative_dex_cache_patches_.size() +
1448      pc_relative_string_patches_.size() +
1449      pc_relative_type_patches_.size() +
1450      type_bss_entry_patches_.size() +
1451      boot_image_string_patches_.size() +
1452      boot_image_type_patches_.size();
1453  linker_patches->reserve(size);
1454  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
1455                                                               linker_patches);
1456  if (!GetCompilerOptions().IsBootImage()) {
1457    DCHECK(pc_relative_type_patches_.empty());
1458    EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
1459                                                                  linker_patches);
1460  } else {
1461    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
1462                                                                linker_patches);
1463    EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
1464                                                                  linker_patches);
1465  }
1466  EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
1467                                                              linker_patches);
1468  for (const auto& entry : boot_image_string_patches_) {
1469    const StringReference& target_string = entry.first;
1470    Literal* literal = entry.second;
1471    DCHECK(literal->GetLabel()->IsBound());
1472    uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1473    linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
1474                                                       target_string.dex_file,
1475                                                       target_string.string_index.index_));
1476  }
1477  for (const auto& entry : boot_image_type_patches_) {
1478    const TypeReference& target_type = entry.first;
1479    Literal* literal = entry.second;
1480    DCHECK(literal->GetLabel()->IsBound());
1481    uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1482    linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
1483                                                     target_type.dex_file,
1484                                                     target_type.type_index.index_));
1485  }
1486  DCHECK_EQ(size, linker_patches->size());
1487}
1488
1489CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeStringPatch(
1490    const DexFile& dex_file, dex::StringIndex string_index) {
1491  return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
1492}
1493
1494CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeTypePatch(
1495    const DexFile& dex_file, dex::TypeIndex type_index) {
1496  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
1497}
1498
1499CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewTypeBssEntryPatch(
1500    const DexFile& dex_file, dex::TypeIndex type_index) {
1501  return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
1502}
1503
1504CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeDexCacheArrayPatch(
1505    const DexFile& dex_file, uint32_t element_offset) {
1506  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
1507}
1508
1509CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativePatch(
1510    const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
1511  patches->emplace_back(dex_file, offset_or_index);
1512  return &patches->back();
1513}
1514
1515Literal* CodeGeneratorMIPS64::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
1516  return map->GetOrCreate(
1517      value,
1518      [this, value]() { return __ NewLiteral<uint32_t>(value); });
1519}
1520
1521Literal* CodeGeneratorMIPS64::DeduplicateUint64Literal(uint64_t value) {
1522  return uint64_literals_.GetOrCreate(
1523      value,
1524      [this, value]() { return __ NewLiteral<uint64_t>(value); });
1525}
1526
1527Literal* CodeGeneratorMIPS64::DeduplicateMethodLiteral(MethodReference target_method,
1528                                                       MethodToLiteralMap* map) {
1529  return map->GetOrCreate(
1530      target_method,
1531      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1532}
1533
1534Literal* CodeGeneratorMIPS64::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
1535                                                                dex::StringIndex string_index) {
1536  return boot_image_string_patches_.GetOrCreate(
1537      StringReference(&dex_file, string_index),
1538      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1539}
1540
1541Literal* CodeGeneratorMIPS64::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
1542                                                              dex::TypeIndex type_index) {
1543  return boot_image_type_patches_.GetOrCreate(
1544      TypeReference(&dex_file, type_index),
1545      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1546}
1547
1548Literal* CodeGeneratorMIPS64::DeduplicateBootImageAddressLiteral(uint64_t address) {
1549  return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
1550}
1551
1552void CodeGeneratorMIPS64::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
1553                                                               GpuRegister out) {
1554  __ Bind(&info->pc_rel_label);
1555  // Add the high half of a 32-bit offset to PC.
1556  __ Auipc(out, /* placeholder */ 0x1234);
1557  // The immediately following instruction will add the sign-extended low half of the 32-bit
1558  // offset to `out` (e.g. ld, jialc, daddiu).
1559}
1560
1561Literal* CodeGeneratorMIPS64::DeduplicateJitStringLiteral(const DexFile& dex_file,
1562                                                          dex::StringIndex string_index,
1563                                                          Handle<mirror::String> handle) {
1564  jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
1565                              reinterpret_cast64<uint64_t>(handle.GetReference()));
1566  return jit_string_patches_.GetOrCreate(
1567      StringReference(&dex_file, string_index),
1568      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1569}
1570
1571Literal* CodeGeneratorMIPS64::DeduplicateJitClassLiteral(const DexFile& dex_file,
1572                                                         dex::TypeIndex type_index,
1573                                                         Handle<mirror::Class> handle) {
1574  jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
1575                             reinterpret_cast64<uint64_t>(handle.GetReference()));
1576  return jit_class_patches_.GetOrCreate(
1577      TypeReference(&dex_file, type_index),
1578      [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1579}
1580
1581void CodeGeneratorMIPS64::PatchJitRootUse(uint8_t* code,
1582                                          const uint8_t* roots_data,
1583                                          const Literal* literal,
1584                                          uint64_t index_in_table) const {
1585  uint32_t literal_offset = GetAssembler().GetLabelLocation(literal->GetLabel());
1586  uintptr_t address =
1587      reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
1588  reinterpret_cast<uint32_t*>(code + literal_offset)[0] = dchecked_integral_cast<uint32_t>(address);
1589}
1590
1591void CodeGeneratorMIPS64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
1592  for (const auto& entry : jit_string_patches_) {
1593    const auto& it = jit_string_roots_.find(entry.first);
1594    DCHECK(it != jit_string_roots_.end());
1595    PatchJitRootUse(code, roots_data, entry.second, it->second);
1596  }
1597  for (const auto& entry : jit_class_patches_) {
1598    const auto& it = jit_class_roots_.find(entry.first);
1599    DCHECK(it != jit_class_roots_.end());
1600    PatchJitRootUse(code, roots_data, entry.second, it->second);
1601  }
1602}
1603
1604void CodeGeneratorMIPS64::SetupBlockedRegisters() const {
1605  // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated.
1606  blocked_core_registers_[ZERO] = true;
1607  blocked_core_registers_[K0] = true;
1608  blocked_core_registers_[K1] = true;
1609  blocked_core_registers_[GP] = true;
1610  blocked_core_registers_[SP] = true;
1611  blocked_core_registers_[RA] = true;
1612
1613  // AT, TMP(T8) and TMP2(T3) are used as temporary/scratch
1614  // registers (similar to how AT is used by MIPS assemblers).
1615  blocked_core_registers_[AT] = true;
1616  blocked_core_registers_[TMP] = true;
1617  blocked_core_registers_[TMP2] = true;
1618  blocked_fpu_registers_[FTMP] = true;
1619
1620  // Reserve suspend and thread registers.
1621  blocked_core_registers_[S0] = true;
1622  blocked_core_registers_[TR] = true;
1623
1624  // Reserve T9 for function calls
1625  blocked_core_registers_[T9] = true;
1626
1627  if (GetGraph()->IsDebuggable()) {
1628    // Stubs do not save callee-save floating point registers. If the graph
1629    // is debuggable, we need to deal with these registers differently. For
1630    // now, just block them.
1631    for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1632      blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
1633    }
1634  }
1635}
1636
1637size_t CodeGeneratorMIPS64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1638  __ StoreToOffset(kStoreDoubleword, GpuRegister(reg_id), SP, stack_index);
1639  return kMips64DoublewordSize;
1640}
1641
1642size_t CodeGeneratorMIPS64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1643  __ LoadFromOffset(kLoadDoubleword, GpuRegister(reg_id), SP, stack_index);
1644  return kMips64DoublewordSize;
1645}
1646
1647size_t CodeGeneratorMIPS64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1648  __ StoreFpuToOffset(kStoreDoubleword, FpuRegister(reg_id), SP, stack_index);
1649  return kMips64DoublewordSize;
1650}
1651
1652size_t CodeGeneratorMIPS64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1653  __ LoadFpuFromOffset(kLoadDoubleword, FpuRegister(reg_id), SP, stack_index);
1654  return kMips64DoublewordSize;
1655}
1656
1657void CodeGeneratorMIPS64::DumpCoreRegister(std::ostream& stream, int reg) const {
1658  stream << GpuRegister(reg);
1659}
1660
1661void CodeGeneratorMIPS64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
1662  stream << FpuRegister(reg);
1663}
1664
1665void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint,
1666                                        HInstruction* instruction,
1667                                        uint32_t dex_pc,
1668                                        SlowPathCode* slow_path) {
1669  ValidateInvokeRuntime(entrypoint, instruction, slow_path);
1670  GenerateInvokeRuntime(GetThreadOffset<kMips64PointerSize>(entrypoint).Int32Value());
1671  if (EntrypointRequiresStackMap(entrypoint)) {
1672    RecordPcInfo(instruction, dex_pc, slow_path);
1673  }
1674}
1675
1676void CodeGeneratorMIPS64::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1677                                                              HInstruction* instruction,
1678                                                              SlowPathCode* slow_path) {
1679  ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
1680  GenerateInvokeRuntime(entry_point_offset);
1681}
1682
1683void CodeGeneratorMIPS64::GenerateInvokeRuntime(int32_t entry_point_offset) {
1684  __ LoadFromOffset(kLoadDoubleword, T9, TR, entry_point_offset);
1685  __ Jalr(T9);
1686  __ Nop();
1687}
1688
1689void InstructionCodeGeneratorMIPS64::GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path,
1690                                                                      GpuRegister class_reg) {
1691  __ LoadFromOffset(kLoadWord, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
1692  __ LoadConst32(AT, mirror::Class::kStatusInitialized);
1693  __ Bltc(TMP, AT, slow_path->GetEntryLabel());
1694  // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1695  __ Sync(0);
1696  __ Bind(slow_path->GetExitLabel());
1697}
1698
1699void InstructionCodeGeneratorMIPS64::GenerateMemoryBarrier(MemBarrierKind kind ATTRIBUTE_UNUSED) {
1700  __ Sync(0);  // only stype 0 is supported
1701}
1702
1703void InstructionCodeGeneratorMIPS64::GenerateSuspendCheck(HSuspendCheck* instruction,
1704                                                          HBasicBlock* successor) {
1705  SuspendCheckSlowPathMIPS64* slow_path =
1706    new (GetGraph()->GetArena()) SuspendCheckSlowPathMIPS64(instruction, successor);
1707  codegen_->AddSlowPath(slow_path);
1708
1709  __ LoadFromOffset(kLoadUnsignedHalfword,
1710                    TMP,
1711                    TR,
1712                    Thread::ThreadFlagsOffset<kMips64PointerSize>().Int32Value());
1713  if (successor == nullptr) {
1714    __ Bnezc(TMP, slow_path->GetEntryLabel());
1715    __ Bind(slow_path->GetReturnLabel());
1716  } else {
1717    __ Beqzc(TMP, codegen_->GetLabelOf(successor));
1718    __ Bc(slow_path->GetEntryLabel());
1719    // slow_path will return to GetLabelOf(successor).
1720  }
1721}
1722
1723InstructionCodeGeneratorMIPS64::InstructionCodeGeneratorMIPS64(HGraph* graph,
1724                                                               CodeGeneratorMIPS64* codegen)
1725      : InstructionCodeGenerator(graph, codegen),
1726        assembler_(codegen->GetAssembler()),
1727        codegen_(codegen) {}
1728
1729void LocationsBuilderMIPS64::HandleBinaryOp(HBinaryOperation* instruction) {
1730  DCHECK_EQ(instruction->InputCount(), 2U);
1731  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1732  Primitive::Type type = instruction->GetResultType();
1733  switch (type) {
1734    case Primitive::kPrimInt:
1735    case Primitive::kPrimLong: {
1736      locations->SetInAt(0, Location::RequiresRegister());
1737      HInstruction* right = instruction->InputAt(1);
1738      bool can_use_imm = false;
1739      if (right->IsConstant()) {
1740        int64_t imm = CodeGenerator::GetInt64ValueOf(right->AsConstant());
1741        if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
1742          can_use_imm = IsUint<16>(imm);
1743        } else if (instruction->IsAdd()) {
1744          can_use_imm = IsInt<16>(imm);
1745        } else {
1746          DCHECK(instruction->IsSub());
1747          can_use_imm = IsInt<16>(-imm);
1748        }
1749      }
1750      if (can_use_imm)
1751        locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
1752      else
1753        locations->SetInAt(1, Location::RequiresRegister());
1754      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1755      }
1756      break;
1757
1758    case Primitive::kPrimFloat:
1759    case Primitive::kPrimDouble:
1760      locations->SetInAt(0, Location::RequiresFpuRegister());
1761      locations->SetInAt(1, Location::RequiresFpuRegister());
1762      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1763      break;
1764
1765    default:
1766      LOG(FATAL) << "Unexpected " << instruction->DebugName() << " type " << type;
1767  }
1768}
1769
1770void InstructionCodeGeneratorMIPS64::HandleBinaryOp(HBinaryOperation* instruction) {
1771  Primitive::Type type = instruction->GetType();
1772  LocationSummary* locations = instruction->GetLocations();
1773
1774  switch (type) {
1775    case Primitive::kPrimInt:
1776    case Primitive::kPrimLong: {
1777      GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
1778      GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
1779      Location rhs_location = locations->InAt(1);
1780
1781      GpuRegister rhs_reg = ZERO;
1782      int64_t rhs_imm = 0;
1783      bool use_imm = rhs_location.IsConstant();
1784      if (use_imm) {
1785        rhs_imm = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant());
1786      } else {
1787        rhs_reg = rhs_location.AsRegister<GpuRegister>();
1788      }
1789
1790      if (instruction->IsAnd()) {
1791        if (use_imm)
1792          __ Andi(dst, lhs, rhs_imm);
1793        else
1794          __ And(dst, lhs, rhs_reg);
1795      } else if (instruction->IsOr()) {
1796        if (use_imm)
1797          __ Ori(dst, lhs, rhs_imm);
1798        else
1799          __ Or(dst, lhs, rhs_reg);
1800      } else if (instruction->IsXor()) {
1801        if (use_imm)
1802          __ Xori(dst, lhs, rhs_imm);
1803        else
1804          __ Xor(dst, lhs, rhs_reg);
1805      } else if (instruction->IsAdd()) {
1806        if (type == Primitive::kPrimInt) {
1807          if (use_imm)
1808            __ Addiu(dst, lhs, rhs_imm);
1809          else
1810            __ Addu(dst, lhs, rhs_reg);
1811        } else {
1812          if (use_imm)
1813            __ Daddiu(dst, lhs, rhs_imm);
1814          else
1815            __ Daddu(dst, lhs, rhs_reg);
1816        }
1817      } else {
1818        DCHECK(instruction->IsSub());
1819        if (type == Primitive::kPrimInt) {
1820          if (use_imm)
1821            __ Addiu(dst, lhs, -rhs_imm);
1822          else
1823            __ Subu(dst, lhs, rhs_reg);
1824        } else {
1825          if (use_imm)
1826            __ Daddiu(dst, lhs, -rhs_imm);
1827          else
1828            __ Dsubu(dst, lhs, rhs_reg);
1829        }
1830      }
1831      break;
1832    }
1833    case Primitive::kPrimFloat:
1834    case Primitive::kPrimDouble: {
1835      FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
1836      FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
1837      FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
1838      if (instruction->IsAdd()) {
1839        if (type == Primitive::kPrimFloat)
1840          __ AddS(dst, lhs, rhs);
1841        else
1842          __ AddD(dst, lhs, rhs);
1843      } else if (instruction->IsSub()) {
1844        if (type == Primitive::kPrimFloat)
1845          __ SubS(dst, lhs, rhs);
1846        else
1847          __ SubD(dst, lhs, rhs);
1848      } else {
1849        LOG(FATAL) << "Unexpected floating-point binary operation";
1850      }
1851      break;
1852    }
1853    default:
1854      LOG(FATAL) << "Unexpected binary operation type " << type;
1855  }
1856}
1857
1858void LocationsBuilderMIPS64::HandleShift(HBinaryOperation* instr) {
1859  DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
1860
1861  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1862  Primitive::Type type = instr->GetResultType();
1863  switch (type) {
1864    case Primitive::kPrimInt:
1865    case Primitive::kPrimLong: {
1866      locations->SetInAt(0, Location::RequiresRegister());
1867      locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1868      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1869      break;
1870    }
1871    default:
1872      LOG(FATAL) << "Unexpected shift type " << type;
1873  }
1874}
1875
1876void InstructionCodeGeneratorMIPS64::HandleShift(HBinaryOperation* instr) {
1877  DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
1878  LocationSummary* locations = instr->GetLocations();
1879  Primitive::Type type = instr->GetType();
1880
1881  switch (type) {
1882    case Primitive::kPrimInt:
1883    case Primitive::kPrimLong: {
1884      GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
1885      GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
1886      Location rhs_location = locations->InAt(1);
1887
1888      GpuRegister rhs_reg = ZERO;
1889      int64_t rhs_imm = 0;
1890      bool use_imm = rhs_location.IsConstant();
1891      if (use_imm) {
1892        rhs_imm = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant());
1893      } else {
1894        rhs_reg = rhs_location.AsRegister<GpuRegister>();
1895      }
1896
1897      if (use_imm) {
1898        uint32_t shift_value = rhs_imm &
1899            (type == Primitive::kPrimInt ? kMaxIntShiftDistance : kMaxLongShiftDistance);
1900
1901        if (shift_value == 0) {
1902          if (dst != lhs) {
1903            __ Move(dst, lhs);
1904          }
1905        } else if (type == Primitive::kPrimInt) {
1906          if (instr->IsShl()) {
1907            __ Sll(dst, lhs, shift_value);
1908          } else if (instr->IsShr()) {
1909            __ Sra(dst, lhs, shift_value);
1910          } else if (instr->IsUShr()) {
1911            __ Srl(dst, lhs, shift_value);
1912          } else {
1913            __ Rotr(dst, lhs, shift_value);
1914          }
1915        } else {
1916          if (shift_value < 32) {
1917            if (instr->IsShl()) {
1918              __ Dsll(dst, lhs, shift_value);
1919            } else if (instr->IsShr()) {
1920              __ Dsra(dst, lhs, shift_value);
1921            } else if (instr->IsUShr()) {
1922              __ Dsrl(dst, lhs, shift_value);
1923            } else {
1924              __ Drotr(dst, lhs, shift_value);
1925            }
1926          } else {
1927            shift_value -= 32;
1928            if (instr->IsShl()) {
1929              __ Dsll32(dst, lhs, shift_value);
1930            } else if (instr->IsShr()) {
1931              __ Dsra32(dst, lhs, shift_value);
1932            } else if (instr->IsUShr()) {
1933              __ Dsrl32(dst, lhs, shift_value);
1934            } else {
1935              __ Drotr32(dst, lhs, shift_value);
1936            }
1937          }
1938        }
1939      } else {
1940        if (type == Primitive::kPrimInt) {
1941          if (instr->IsShl()) {
1942            __ Sllv(dst, lhs, rhs_reg);
1943          } else if (instr->IsShr()) {
1944            __ Srav(dst, lhs, rhs_reg);
1945          } else if (instr->IsUShr()) {
1946            __ Srlv(dst, lhs, rhs_reg);
1947          } else {
1948            __ Rotrv(dst, lhs, rhs_reg);
1949          }
1950        } else {
1951          if (instr->IsShl()) {
1952            __ Dsllv(dst, lhs, rhs_reg);
1953          } else if (instr->IsShr()) {
1954            __ Dsrav(dst, lhs, rhs_reg);
1955          } else if (instr->IsUShr()) {
1956            __ Dsrlv(dst, lhs, rhs_reg);
1957          } else {
1958            __ Drotrv(dst, lhs, rhs_reg);
1959          }
1960        }
1961      }
1962      break;
1963    }
1964    default:
1965      LOG(FATAL) << "Unexpected shift operation type " << type;
1966  }
1967}
1968
1969void LocationsBuilderMIPS64::VisitAdd(HAdd* instruction) {
1970  HandleBinaryOp(instruction);
1971}
1972
1973void InstructionCodeGeneratorMIPS64::VisitAdd(HAdd* instruction) {
1974  HandleBinaryOp(instruction);
1975}
1976
1977void LocationsBuilderMIPS64::VisitAnd(HAnd* instruction) {
1978  HandleBinaryOp(instruction);
1979}
1980
1981void InstructionCodeGeneratorMIPS64::VisitAnd(HAnd* instruction) {
1982  HandleBinaryOp(instruction);
1983}
1984
1985void LocationsBuilderMIPS64::VisitArrayGet(HArrayGet* instruction) {
1986  Primitive::Type type = instruction->GetType();
1987  bool object_array_get_with_read_barrier =
1988      kEmitCompilerReadBarrier && (type == Primitive::kPrimNot);
1989  LocationSummary* locations =
1990      new (GetGraph()->GetArena()) LocationSummary(instruction,
1991                                                   object_array_get_with_read_barrier
1992                                                       ? LocationSummary::kCallOnSlowPath
1993                                                       : LocationSummary::kNoCall);
1994  locations->SetInAt(0, Location::RequiresRegister());
1995  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1996  if (Primitive::IsFloatingPointType(type)) {
1997    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1998  } else {
1999    // The output overlaps in the case of an object array get with
2000    // read barriers enabled: we do not want the move to overwrite the
2001    // array's location, as we need it to emit the read barrier.
2002    locations->SetOut(Location::RequiresRegister(),
2003                      object_array_get_with_read_barrier
2004                          ? Location::kOutputOverlap
2005                          : Location::kNoOutputOverlap);
2006  }
2007  // We need a temporary register for the read barrier marking slow
2008  // path in CodeGeneratorMIPS64::GenerateArrayLoadWithBakerReadBarrier.
2009  if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
2010    locations->AddTemp(Location::RequiresRegister());
2011  }
2012}
2013
2014static auto GetImplicitNullChecker(HInstruction* instruction, CodeGeneratorMIPS64* codegen) {
2015  auto null_checker = [codegen, instruction]() {
2016    codegen->MaybeRecordImplicitNullCheck(instruction);
2017  };
2018  return null_checker;
2019}
2020
2021void InstructionCodeGeneratorMIPS64::VisitArrayGet(HArrayGet* instruction) {
2022  LocationSummary* locations = instruction->GetLocations();
2023  Location obj_loc = locations->InAt(0);
2024  GpuRegister obj = obj_loc.AsRegister<GpuRegister>();
2025  Location out_loc = locations->Out();
2026  Location index = locations->InAt(1);
2027  uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
2028  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
2029
2030  Primitive::Type type = instruction->GetType();
2031  const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
2032                                        instruction->IsStringCharAt();
2033  switch (type) {
2034    case Primitive::kPrimBoolean: {
2035      GpuRegister out = out_loc.AsRegister<GpuRegister>();
2036      if (index.IsConstant()) {
2037        size_t offset =
2038            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2039        __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
2040      } else {
2041        __ Daddu(TMP, obj, index.AsRegister<GpuRegister>());
2042        __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
2043      }
2044      break;
2045    }
2046
2047    case Primitive::kPrimByte: {
2048      GpuRegister out = out_loc.AsRegister<GpuRegister>();
2049      if (index.IsConstant()) {
2050        size_t offset =
2051            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
2052        __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
2053      } else {
2054        __ Daddu(TMP, obj, index.AsRegister<GpuRegister>());
2055        __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
2056      }
2057      break;
2058    }
2059
2060    case Primitive::kPrimShort: {
2061      GpuRegister out = out_loc.AsRegister<GpuRegister>();
2062      if (index.IsConstant()) {
2063        size_t offset =
2064            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2065        __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
2066      } else {
2067        __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_2);
2068        __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
2069      }
2070      break;
2071    }
2072
2073    case Primitive::kPrimChar: {
2074      GpuRegister out = out_loc.AsRegister<GpuRegister>();
2075      if (maybe_compressed_char_at) {
2076        uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2077        __ LoadFromOffset(kLoadWord, TMP, obj, count_offset, null_checker);
2078        __ Dext(TMP, TMP, 0, 1);
2079        static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2080                      "Expecting 0=compressed, 1=uncompressed");
2081      }
2082      if (index.IsConstant()) {
2083        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
2084        if (maybe_compressed_char_at) {
2085          Mips64Label uncompressed_load, done;
2086          __ Bnezc(TMP, &uncompressed_load);
2087          __ LoadFromOffset(kLoadUnsignedByte,
2088                            out,
2089                            obj,
2090                            data_offset + (const_index << TIMES_1));
2091          __ Bc(&done);
2092          __ Bind(&uncompressed_load);
2093          __ LoadFromOffset(kLoadUnsignedHalfword,
2094                            out,
2095                            obj,
2096                            data_offset + (const_index << TIMES_2));
2097          __ Bind(&done);
2098        } else {
2099          __ LoadFromOffset(kLoadUnsignedHalfword,
2100                            out,
2101                            obj,
2102                            data_offset + (const_index << TIMES_2),
2103                            null_checker);
2104        }
2105      } else {
2106        GpuRegister index_reg = index.AsRegister<GpuRegister>();
2107        if (maybe_compressed_char_at) {
2108          Mips64Label uncompressed_load, done;
2109          __ Bnezc(TMP, &uncompressed_load);
2110          __ Daddu(TMP, obj, index_reg);
2111          __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
2112          __ Bc(&done);
2113          __ Bind(&uncompressed_load);
2114          __ Dlsa(TMP, index_reg, obj, TIMES_2);
2115          __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
2116          __ Bind(&done);
2117        } else {
2118          __ Dlsa(TMP, index_reg, obj, TIMES_2);
2119          __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
2120        }
2121      }
2122      break;
2123    }
2124
2125    case Primitive::kPrimInt: {
2126      DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
2127      GpuRegister out = out_loc.AsRegister<GpuRegister>();
2128      LoadOperandType load_type = (type == Primitive::kPrimNot) ? kLoadUnsignedWord : kLoadWord;
2129      if (index.IsConstant()) {
2130        size_t offset =
2131            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2132        __ LoadFromOffset(load_type, out, obj, offset, null_checker);
2133      } else {
2134        __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2135        __ LoadFromOffset(load_type, out, TMP, data_offset, null_checker);
2136      }
2137      break;
2138    }
2139
2140    case Primitive::kPrimNot: {
2141      static_assert(
2142          sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
2143          "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
2144      // /* HeapReference<Object> */ out =
2145      //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
2146      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
2147        Location temp = locations->GetTemp(0);
2148        // Note that a potential implicit null check is handled in this
2149        // CodeGeneratorMIPS64::GenerateArrayLoadWithBakerReadBarrier call.
2150        codegen_->GenerateArrayLoadWithBakerReadBarrier(instruction,
2151                                                        out_loc,
2152                                                        obj,
2153                                                        data_offset,
2154                                                        index,
2155                                                        temp,
2156                                                        /* needs_null_check */ true);
2157      } else {
2158        GpuRegister out = out_loc.AsRegister<GpuRegister>();
2159        if (index.IsConstant()) {
2160          size_t offset =
2161              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2162          __ LoadFromOffset(kLoadUnsignedWord, out, obj, offset, null_checker);
2163          // If read barriers are enabled, emit read barriers other than
2164          // Baker's using a slow path (and also unpoison the loaded
2165          // reference, if heap poisoning is enabled).
2166          codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
2167        } else {
2168          __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2169          __ LoadFromOffset(kLoadUnsignedWord, out, TMP, data_offset, null_checker);
2170          // If read barriers are enabled, emit read barriers other than
2171          // Baker's using a slow path (and also unpoison the loaded
2172          // reference, if heap poisoning is enabled).
2173          codegen_->MaybeGenerateReadBarrierSlow(instruction,
2174                                                 out_loc,
2175                                                 out_loc,
2176                                                 obj_loc,
2177                                                 data_offset,
2178                                                 index);
2179        }
2180      }
2181      break;
2182    }
2183
2184    case Primitive::kPrimLong: {
2185      GpuRegister out = out_loc.AsRegister<GpuRegister>();
2186      if (index.IsConstant()) {
2187        size_t offset =
2188            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
2189        __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
2190      } else {
2191        __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_8);
2192        __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
2193      }
2194      break;
2195    }
2196
2197    case Primitive::kPrimFloat: {
2198      FpuRegister out = out_loc.AsFpuRegister<FpuRegister>();
2199      if (index.IsConstant()) {
2200        size_t offset =
2201            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2202        __ LoadFpuFromOffset(kLoadWord, out, obj, offset, null_checker);
2203      } else {
2204        __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2205        __ LoadFpuFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
2206      }
2207      break;
2208    }
2209
2210    case Primitive::kPrimDouble: {
2211      FpuRegister out = out_loc.AsFpuRegister<FpuRegister>();
2212      if (index.IsConstant()) {
2213        size_t offset =
2214            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
2215        __ LoadFpuFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
2216      } else {
2217        __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_8);
2218        __ LoadFpuFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
2219      }
2220      break;
2221    }
2222
2223    case Primitive::kPrimVoid:
2224      LOG(FATAL) << "Unreachable type " << instruction->GetType();
2225      UNREACHABLE();
2226  }
2227}
2228
2229void LocationsBuilderMIPS64::VisitArrayLength(HArrayLength* instruction) {
2230  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2231  locations->SetInAt(0, Location::RequiresRegister());
2232  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2233}
2234
2235void InstructionCodeGeneratorMIPS64::VisitArrayLength(HArrayLength* instruction) {
2236  LocationSummary* locations = instruction->GetLocations();
2237  uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
2238  GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>();
2239  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
2240  __ LoadFromOffset(kLoadWord, out, obj, offset);
2241  codegen_->MaybeRecordImplicitNullCheck(instruction);
2242  // Mask out compression flag from String's array length.
2243  if (mirror::kUseStringCompression && instruction->IsStringLength()) {
2244    __ Srl(out, out, 1u);
2245  }
2246}
2247
2248Location LocationsBuilderMIPS64::RegisterOrZeroConstant(HInstruction* instruction) {
2249  return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern())
2250      ? Location::ConstantLocation(instruction->AsConstant())
2251      : Location::RequiresRegister();
2252}
2253
2254Location LocationsBuilderMIPS64::FpuRegisterOrConstantForStore(HInstruction* instruction) {
2255  // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register.
2256  // We can store a non-zero float or double constant without first loading it into the FPU,
2257  // but we should only prefer this if the constant has a single use.
2258  if (instruction->IsConstant() &&
2259      (instruction->AsConstant()->IsZeroBitPattern() ||
2260       instruction->GetUses().HasExactlyOneElement())) {
2261    return Location::ConstantLocation(instruction->AsConstant());
2262    // Otherwise fall through and require an FPU register for the constant.
2263  }
2264  return Location::RequiresFpuRegister();
2265}
2266
2267void LocationsBuilderMIPS64::VisitArraySet(HArraySet* instruction) {
2268  Primitive::Type value_type = instruction->GetComponentType();
2269
2270  bool needs_write_barrier =
2271      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2272  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
2273
2274  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2275      instruction,
2276      may_need_runtime_call_for_type_check ?
2277          LocationSummary::kCallOnSlowPath :
2278          LocationSummary::kNoCall);
2279
2280  locations->SetInAt(0, Location::RequiresRegister());
2281  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2282  if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
2283    locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
2284  } else {
2285    locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
2286  }
2287  if (needs_write_barrier) {
2288    // Temporary register for the write barrier.
2289    locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
2290  }
2291}
2292
2293void InstructionCodeGeneratorMIPS64::VisitArraySet(HArraySet* instruction) {
2294  LocationSummary* locations = instruction->GetLocations();
2295  GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>();
2296  Location index = locations->InAt(1);
2297  Location value_location = locations->InAt(2);
2298  Primitive::Type value_type = instruction->GetComponentType();
2299  bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
2300  bool needs_write_barrier =
2301      CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2302  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
2303  GpuRegister base_reg = index.IsConstant() ? obj : TMP;
2304
2305  switch (value_type) {
2306    case Primitive::kPrimBoolean:
2307    case Primitive::kPrimByte: {
2308      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
2309      if (index.IsConstant()) {
2310        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
2311      } else {
2312        __ Daddu(base_reg, obj, index.AsRegister<GpuRegister>());
2313      }
2314      if (value_location.IsConstant()) {
2315        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2316        __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker);
2317      } else {
2318        GpuRegister value = value_location.AsRegister<GpuRegister>();
2319        __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker);
2320      }
2321      break;
2322    }
2323
2324    case Primitive::kPrimShort:
2325    case Primitive::kPrimChar: {
2326      uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
2327      if (index.IsConstant()) {
2328        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
2329      } else {
2330        __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_2);
2331      }
2332      if (value_location.IsConstant()) {
2333        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2334        __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker);
2335      } else {
2336        GpuRegister value = value_location.AsRegister<GpuRegister>();
2337        __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker);
2338      }
2339      break;
2340    }
2341
2342    case Primitive::kPrimInt: {
2343      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2344      if (index.IsConstant()) {
2345        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2346      } else {
2347        __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2348      }
2349      if (value_location.IsConstant()) {
2350        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2351        __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2352      } else {
2353        GpuRegister value = value_location.AsRegister<GpuRegister>();
2354        __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2355      }
2356      break;
2357    }
2358
2359    case Primitive::kPrimNot: {
2360      if (value_location.IsConstant()) {
2361        // Just setting null.
2362        uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2363        if (index.IsConstant()) {
2364          data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2365        } else {
2366          __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2367        }
2368        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2369        DCHECK_EQ(value, 0);
2370        __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2371        DCHECK(!needs_write_barrier);
2372        DCHECK(!may_need_runtime_call_for_type_check);
2373        break;
2374      }
2375
2376      DCHECK(needs_write_barrier);
2377      GpuRegister value = value_location.AsRegister<GpuRegister>();
2378      GpuRegister temp1 = locations->GetTemp(0).AsRegister<GpuRegister>();
2379      GpuRegister temp2 = TMP;  // Doesn't need to survive slow path.
2380      uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2381      uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
2382      uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
2383      Mips64Label done;
2384      SlowPathCodeMIPS64* slow_path = nullptr;
2385
2386      if (may_need_runtime_call_for_type_check) {
2387        slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathMIPS64(instruction);
2388        codegen_->AddSlowPath(slow_path);
2389        if (instruction->GetValueCanBeNull()) {
2390          Mips64Label non_zero;
2391          __ Bnezc(value, &non_zero);
2392          uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2393          if (index.IsConstant()) {
2394            data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2395          } else {
2396            __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2397          }
2398          __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2399          __ Bc(&done);
2400          __ Bind(&non_zero);
2401        }
2402
2403        // Note that when read barriers are enabled, the type checks
2404        // are performed without read barriers.  This is fine, even in
2405        // the case where a class object is in the from-space after
2406        // the flip, as a comparison involving such a type would not
2407        // produce a false positive; it may of course produce a false
2408        // negative, in which case we would take the ArraySet slow
2409        // path.
2410
2411        // /* HeapReference<Class> */ temp1 = obj->klass_
2412        __ LoadFromOffset(kLoadUnsignedWord, temp1, obj, class_offset, null_checker);
2413        __ MaybeUnpoisonHeapReference(temp1);
2414
2415        // /* HeapReference<Class> */ temp1 = temp1->component_type_
2416        __ LoadFromOffset(kLoadUnsignedWord, temp1, temp1, component_offset);
2417        // /* HeapReference<Class> */ temp2 = value->klass_
2418        __ LoadFromOffset(kLoadUnsignedWord, temp2, value, class_offset);
2419        // If heap poisoning is enabled, no need to unpoison `temp1`
2420        // nor `temp2`, as we are comparing two poisoned references.
2421
2422        if (instruction->StaticTypeOfArrayIsObjectArray()) {
2423          Mips64Label do_put;
2424          __ Beqc(temp1, temp2, &do_put);
2425          // If heap poisoning is enabled, the `temp1` reference has
2426          // not been unpoisoned yet; unpoison it now.
2427          __ MaybeUnpoisonHeapReference(temp1);
2428
2429          // /* HeapReference<Class> */ temp1 = temp1->super_class_
2430          __ LoadFromOffset(kLoadUnsignedWord, temp1, temp1, super_offset);
2431          // If heap poisoning is enabled, no need to unpoison
2432          // `temp1`, as we are comparing against null below.
2433          __ Bnezc(temp1, slow_path->GetEntryLabel());
2434          __ Bind(&do_put);
2435        } else {
2436          __ Bnec(temp1, temp2, slow_path->GetEntryLabel());
2437        }
2438      }
2439
2440      GpuRegister source = value;
2441      if (kPoisonHeapReferences) {
2442        // Note that in the case where `value` is a null reference,
2443        // we do not enter this block, as a null reference does not
2444        // need poisoning.
2445        __ Move(temp1, value);
2446        __ PoisonHeapReference(temp1);
2447        source = temp1;
2448      }
2449
2450      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2451      if (index.IsConstant()) {
2452        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2453      } else {
2454        __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2455      }
2456      __ StoreToOffset(kStoreWord, source, base_reg, data_offset);
2457
2458      if (!may_need_runtime_call_for_type_check) {
2459        codegen_->MaybeRecordImplicitNullCheck(instruction);
2460      }
2461
2462      codegen_->MarkGCCard(obj, value, instruction->GetValueCanBeNull());
2463
2464      if (done.IsLinked()) {
2465        __ Bind(&done);
2466      }
2467
2468      if (slow_path != nullptr) {
2469        __ Bind(slow_path->GetExitLabel());
2470      }
2471      break;
2472    }
2473
2474    case Primitive::kPrimLong: {
2475      uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
2476      if (index.IsConstant()) {
2477        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
2478      } else {
2479        __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_8);
2480      }
2481      if (value_location.IsConstant()) {
2482        int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2483        __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2484      } else {
2485        GpuRegister value = value_location.AsRegister<GpuRegister>();
2486        __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker);
2487      }
2488      break;
2489    }
2490
2491    case Primitive::kPrimFloat: {
2492      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
2493      if (index.IsConstant()) {
2494        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
2495      } else {
2496        __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_4);
2497      }
2498      if (value_location.IsConstant()) {
2499        int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2500        __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2501      } else {
2502        FpuRegister value = value_location.AsFpuRegister<FpuRegister>();
2503        __ StoreFpuToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2504      }
2505      break;
2506    }
2507
2508    case Primitive::kPrimDouble: {
2509      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
2510      if (index.IsConstant()) {
2511        data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
2512      } else {
2513        __ Dlsa(base_reg, index.AsRegister<GpuRegister>(), obj, TIMES_8);
2514      }
2515      if (value_location.IsConstant()) {
2516        int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2517        __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2518      } else {
2519        FpuRegister value = value_location.AsFpuRegister<FpuRegister>();
2520        __ StoreFpuToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker);
2521      }
2522      break;
2523    }
2524
2525    case Primitive::kPrimVoid:
2526      LOG(FATAL) << "Unreachable type " << instruction->GetType();
2527      UNREACHABLE();
2528  }
2529}
2530
2531void LocationsBuilderMIPS64::VisitBoundsCheck(HBoundsCheck* instruction) {
2532  RegisterSet caller_saves = RegisterSet::Empty();
2533  InvokeRuntimeCallingConvention calling_convention;
2534  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2535  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2536  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
2537  locations->SetInAt(0, Location::RequiresRegister());
2538  locations->SetInAt(1, Location::RequiresRegister());
2539}
2540
2541void InstructionCodeGeneratorMIPS64::VisitBoundsCheck(HBoundsCheck* instruction) {
2542  LocationSummary* locations = instruction->GetLocations();
2543  BoundsCheckSlowPathMIPS64* slow_path =
2544      new (GetGraph()->GetArena()) BoundsCheckSlowPathMIPS64(instruction);
2545  codegen_->AddSlowPath(slow_path);
2546
2547  GpuRegister index = locations->InAt(0).AsRegister<GpuRegister>();
2548  GpuRegister length = locations->InAt(1).AsRegister<GpuRegister>();
2549
2550  // length is limited by the maximum positive signed 32-bit integer.
2551  // Unsigned comparison of length and index checks for index < 0
2552  // and for length <= index simultaneously.
2553  __ Bgeuc(index, length, slow_path->GetEntryLabel());
2554}
2555
2556// Temp is used for read barrier.
2557static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
2558  if (kEmitCompilerReadBarrier &&
2559      (kUseBakerReadBarrier ||
2560       type_check_kind == TypeCheckKind::kAbstractClassCheck ||
2561       type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
2562       type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
2563    return 1;
2564  }
2565  return 0;
2566}
2567
2568// Extra temp is used for read barrier.
2569static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
2570  return 1 + NumberOfInstanceOfTemps(type_check_kind);
2571}
2572
2573void LocationsBuilderMIPS64::VisitCheckCast(HCheckCast* instruction) {
2574  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
2575  bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
2576
2577  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
2578  switch (type_check_kind) {
2579    case TypeCheckKind::kExactCheck:
2580    case TypeCheckKind::kAbstractClassCheck:
2581    case TypeCheckKind::kClassHierarchyCheck:
2582    case TypeCheckKind::kArrayObjectCheck:
2583      call_kind = (throws_into_catch || kEmitCompilerReadBarrier)
2584          ? LocationSummary::kCallOnSlowPath
2585          : LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
2586      break;
2587    case TypeCheckKind::kArrayCheck:
2588    case TypeCheckKind::kUnresolvedCheck:
2589    case TypeCheckKind::kInterfaceCheck:
2590      call_kind = LocationSummary::kCallOnSlowPath;
2591      break;
2592  }
2593
2594  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
2595  locations->SetInAt(0, Location::RequiresRegister());
2596  locations->SetInAt(1, Location::RequiresRegister());
2597  locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
2598}
2599
2600void InstructionCodeGeneratorMIPS64::VisitCheckCast(HCheckCast* instruction) {
2601  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
2602  LocationSummary* locations = instruction->GetLocations();
2603  Location obj_loc = locations->InAt(0);
2604  GpuRegister obj = obj_loc.AsRegister<GpuRegister>();
2605  GpuRegister cls = locations->InAt(1).AsRegister<GpuRegister>();
2606  Location temp_loc = locations->GetTemp(0);
2607  GpuRegister temp = temp_loc.AsRegister<GpuRegister>();
2608  const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
2609  DCHECK_LE(num_temps, 2u);
2610  Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
2611  const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2612  const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
2613  const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
2614  const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
2615  const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
2616  const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
2617  const uint32_t object_array_data_offset =
2618      mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
2619  Mips64Label done;
2620
2621  // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
2622  // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
2623  // read barriers is done for performance and code size reasons.
2624  bool is_type_check_slow_path_fatal = false;
2625  if (!kEmitCompilerReadBarrier) {
2626    is_type_check_slow_path_fatal =
2627        (type_check_kind == TypeCheckKind::kExactCheck ||
2628         type_check_kind == TypeCheckKind::kAbstractClassCheck ||
2629         type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
2630         type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
2631        !instruction->CanThrowIntoCatchBlock();
2632  }
2633  SlowPathCodeMIPS64* slow_path =
2634      new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS64(instruction,
2635                                                           is_type_check_slow_path_fatal);
2636  codegen_->AddSlowPath(slow_path);
2637
2638  // Avoid this check if we know `obj` is not null.
2639  if (instruction->MustDoNullCheck()) {
2640    __ Beqzc(obj, &done);
2641  }
2642
2643  switch (type_check_kind) {
2644    case TypeCheckKind::kExactCheck:
2645    case TypeCheckKind::kArrayCheck: {
2646      // /* HeapReference<Class> */ temp = obj->klass_
2647      GenerateReferenceLoadTwoRegisters(instruction,
2648                                        temp_loc,
2649                                        obj_loc,
2650                                        class_offset,
2651                                        maybe_temp2_loc,
2652                                        kWithoutReadBarrier);
2653      // Jump to slow path for throwing the exception or doing a
2654      // more involved array check.
2655      __ Bnec(temp, cls, slow_path->GetEntryLabel());
2656      break;
2657    }
2658
2659    case TypeCheckKind::kAbstractClassCheck: {
2660      // /* HeapReference<Class> */ temp = obj->klass_
2661      GenerateReferenceLoadTwoRegisters(instruction,
2662                                        temp_loc,
2663                                        obj_loc,
2664                                        class_offset,
2665                                        maybe_temp2_loc,
2666                                        kWithoutReadBarrier);
2667      // If the class is abstract, we eagerly fetch the super class of the
2668      // object to avoid doing a comparison we know will fail.
2669      Mips64Label loop;
2670      __ Bind(&loop);
2671      // /* HeapReference<Class> */ temp = temp->super_class_
2672      GenerateReferenceLoadOneRegister(instruction,
2673                                       temp_loc,
2674                                       super_offset,
2675                                       maybe_temp2_loc,
2676                                       kWithoutReadBarrier);
2677      // If the class reference currently in `temp` is null, jump to the slow path to throw the
2678      // exception.
2679      __ Beqzc(temp, slow_path->GetEntryLabel());
2680      // Otherwise, compare the classes.
2681      __ Bnec(temp, cls, &loop);
2682      break;
2683    }
2684
2685    case TypeCheckKind::kClassHierarchyCheck: {
2686      // /* HeapReference<Class> */ temp = obj->klass_
2687      GenerateReferenceLoadTwoRegisters(instruction,
2688                                        temp_loc,
2689                                        obj_loc,
2690                                        class_offset,
2691                                        maybe_temp2_loc,
2692                                        kWithoutReadBarrier);
2693      // Walk over the class hierarchy to find a match.
2694      Mips64Label loop;
2695      __ Bind(&loop);
2696      __ Beqc(temp, cls, &done);
2697      // /* HeapReference<Class> */ temp = temp->super_class_
2698      GenerateReferenceLoadOneRegister(instruction,
2699                                       temp_loc,
2700                                       super_offset,
2701                                       maybe_temp2_loc,
2702                                       kWithoutReadBarrier);
2703      // If the class reference currently in `temp` is null, jump to the slow path to throw the
2704      // exception. Otherwise, jump to the beginning of the loop.
2705      __ Bnezc(temp, &loop);
2706      __ Bc(slow_path->GetEntryLabel());
2707      break;
2708    }
2709
2710    case TypeCheckKind::kArrayObjectCheck: {
2711      // /* HeapReference<Class> */ temp = obj->klass_
2712      GenerateReferenceLoadTwoRegisters(instruction,
2713                                        temp_loc,
2714                                        obj_loc,
2715                                        class_offset,
2716                                        maybe_temp2_loc,
2717                                        kWithoutReadBarrier);
2718      // Do an exact check.
2719      __ Beqc(temp, cls, &done);
2720      // Otherwise, we need to check that the object's class is a non-primitive array.
2721      // /* HeapReference<Class> */ temp = temp->component_type_
2722      GenerateReferenceLoadOneRegister(instruction,
2723                                       temp_loc,
2724                                       component_offset,
2725                                       maybe_temp2_loc,
2726                                       kWithoutReadBarrier);
2727      // If the component type is null, jump to the slow path to throw the exception.
2728      __ Beqzc(temp, slow_path->GetEntryLabel());
2729      // Otherwise, the object is indeed an array, further check that this component
2730      // type is not a primitive type.
2731      __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
2732      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
2733      __ Bnezc(temp, slow_path->GetEntryLabel());
2734      break;
2735    }
2736
2737    case TypeCheckKind::kUnresolvedCheck:
2738      // We always go into the type check slow path for the unresolved check case.
2739      // We cannot directly call the CheckCast runtime entry point
2740      // without resorting to a type checking slow path here (i.e. by
2741      // calling InvokeRuntime directly), as it would require to
2742      // assign fixed registers for the inputs of this HInstanceOf
2743      // instruction (following the runtime calling convention), which
2744      // might be cluttered by the potential first read barrier
2745      // emission at the beginning of this method.
2746      __ Bc(slow_path->GetEntryLabel());
2747      break;
2748
2749    case TypeCheckKind::kInterfaceCheck: {
2750      // Avoid read barriers to improve performance of the fast path. We can not get false
2751      // positives by doing this.
2752      // /* HeapReference<Class> */ temp = obj->klass_
2753      GenerateReferenceLoadTwoRegisters(instruction,
2754                                        temp_loc,
2755                                        obj_loc,
2756                                        class_offset,
2757                                        maybe_temp2_loc,
2758                                        kWithoutReadBarrier);
2759      // /* HeapReference<Class> */ temp = temp->iftable_
2760      GenerateReferenceLoadTwoRegisters(instruction,
2761                                        temp_loc,
2762                                        temp_loc,
2763                                        iftable_offset,
2764                                        maybe_temp2_loc,
2765                                        kWithoutReadBarrier);
2766      // Iftable is never null.
2767      __ Lw(TMP, temp, array_length_offset);
2768      // Loop through the iftable and check if any class matches.
2769      Mips64Label loop;
2770      __ Bind(&loop);
2771      __ Beqzc(TMP, slow_path->GetEntryLabel());
2772      __ Lwu(AT, temp, object_array_data_offset);
2773      __ MaybeUnpoisonHeapReference(AT);
2774      // Go to next interface.
2775      __ Daddiu(temp, temp, 2 * kHeapReferenceSize);
2776      __ Addiu(TMP, TMP, -2);
2777      // Compare the classes and continue the loop if they do not match.
2778      __ Bnec(AT, cls, &loop);
2779      break;
2780    }
2781  }
2782
2783  __ Bind(&done);
2784  __ Bind(slow_path->GetExitLabel());
2785}
2786
2787void LocationsBuilderMIPS64::VisitClinitCheck(HClinitCheck* check) {
2788  LocationSummary* locations =
2789      new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2790  locations->SetInAt(0, Location::RequiresRegister());
2791  if (check->HasUses()) {
2792    locations->SetOut(Location::SameAsFirstInput());
2793  }
2794}
2795
2796void InstructionCodeGeneratorMIPS64::VisitClinitCheck(HClinitCheck* check) {
2797  // We assume the class is not null.
2798  SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS64(
2799      check->GetLoadClass(),
2800      check,
2801      check->GetDexPc(),
2802      true);
2803  codegen_->AddSlowPath(slow_path);
2804  GenerateClassInitializationCheck(slow_path,
2805                                   check->GetLocations()->InAt(0).AsRegister<GpuRegister>());
2806}
2807
2808void LocationsBuilderMIPS64::VisitCompare(HCompare* compare) {
2809  Primitive::Type in_type = compare->InputAt(0)->GetType();
2810
2811  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
2812
2813  switch (in_type) {
2814    case Primitive::kPrimBoolean:
2815    case Primitive::kPrimByte:
2816    case Primitive::kPrimShort:
2817    case Primitive::kPrimChar:
2818    case Primitive::kPrimInt:
2819    case Primitive::kPrimLong:
2820      locations->SetInAt(0, Location::RequiresRegister());
2821      locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
2822      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2823      break;
2824
2825    case Primitive::kPrimFloat:
2826    case Primitive::kPrimDouble:
2827      locations->SetInAt(0, Location::RequiresFpuRegister());
2828      locations->SetInAt(1, Location::RequiresFpuRegister());
2829      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2830      break;
2831
2832    default:
2833      LOG(FATAL) << "Unexpected type for compare operation " << in_type;
2834  }
2835}
2836
2837void InstructionCodeGeneratorMIPS64::VisitCompare(HCompare* instruction) {
2838  LocationSummary* locations = instruction->GetLocations();
2839  GpuRegister res = locations->Out().AsRegister<GpuRegister>();
2840  Primitive::Type in_type = instruction->InputAt(0)->GetType();
2841
2842  //  0 if: left == right
2843  //  1 if: left  > right
2844  // -1 if: left  < right
2845  switch (in_type) {
2846    case Primitive::kPrimBoolean:
2847    case Primitive::kPrimByte:
2848    case Primitive::kPrimShort:
2849    case Primitive::kPrimChar:
2850    case Primitive::kPrimInt:
2851    case Primitive::kPrimLong: {
2852      GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
2853      Location rhs_location = locations->InAt(1);
2854      bool use_imm = rhs_location.IsConstant();
2855      GpuRegister rhs = ZERO;
2856      if (use_imm) {
2857        if (in_type == Primitive::kPrimLong) {
2858          int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
2859          if (value != 0) {
2860            rhs = AT;
2861            __ LoadConst64(rhs, value);
2862          }
2863        } else {
2864          int32_t value = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant()->AsConstant());
2865          if (value != 0) {
2866            rhs = AT;
2867            __ LoadConst32(rhs, value);
2868          }
2869        }
2870      } else {
2871        rhs = rhs_location.AsRegister<GpuRegister>();
2872      }
2873      __ Slt(TMP, lhs, rhs);
2874      __ Slt(res, rhs, lhs);
2875      __ Subu(res, res, TMP);
2876      break;
2877    }
2878
2879    case Primitive::kPrimFloat: {
2880      FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
2881      FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
2882      Mips64Label done;
2883      __ CmpEqS(FTMP, lhs, rhs);
2884      __ LoadConst32(res, 0);
2885      __ Bc1nez(FTMP, &done);
2886      if (instruction->IsGtBias()) {
2887        __ CmpLtS(FTMP, lhs, rhs);
2888        __ LoadConst32(res, -1);
2889        __ Bc1nez(FTMP, &done);
2890        __ LoadConst32(res, 1);
2891      } else {
2892        __ CmpLtS(FTMP, rhs, lhs);
2893        __ LoadConst32(res, 1);
2894        __ Bc1nez(FTMP, &done);
2895        __ LoadConst32(res, -1);
2896      }
2897      __ Bind(&done);
2898      break;
2899    }
2900
2901    case Primitive::kPrimDouble: {
2902      FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
2903      FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
2904      Mips64Label done;
2905      __ CmpEqD(FTMP, lhs, rhs);
2906      __ LoadConst32(res, 0);
2907      __ Bc1nez(FTMP, &done);
2908      if (instruction->IsGtBias()) {
2909        __ CmpLtD(FTMP, lhs, rhs);
2910        __ LoadConst32(res, -1);
2911        __ Bc1nez(FTMP, &done);
2912        __ LoadConst32(res, 1);
2913      } else {
2914        __ CmpLtD(FTMP, rhs, lhs);
2915        __ LoadConst32(res, 1);
2916        __ Bc1nez(FTMP, &done);
2917        __ LoadConst32(res, -1);
2918      }
2919      __ Bind(&done);
2920      break;
2921    }
2922
2923    default:
2924      LOG(FATAL) << "Unimplemented compare type " << in_type;
2925  }
2926}
2927
2928void LocationsBuilderMIPS64::HandleCondition(HCondition* instruction) {
2929  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2930  switch (instruction->InputAt(0)->GetType()) {
2931    default:
2932    case Primitive::kPrimLong:
2933      locations->SetInAt(0, Location::RequiresRegister());
2934      locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2935      break;
2936
2937    case Primitive::kPrimFloat:
2938    case Primitive::kPrimDouble:
2939      locations->SetInAt(0, Location::RequiresFpuRegister());
2940      locations->SetInAt(1, Location::RequiresFpuRegister());
2941      break;
2942  }
2943  if (!instruction->IsEmittedAtUseSite()) {
2944    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2945  }
2946}
2947
2948void InstructionCodeGeneratorMIPS64::HandleCondition(HCondition* instruction) {
2949  if (instruction->IsEmittedAtUseSite()) {
2950    return;
2951  }
2952
2953  Primitive::Type type = instruction->InputAt(0)->GetType();
2954  LocationSummary* locations = instruction->GetLocations();
2955  switch (type) {
2956    default:
2957      // Integer case.
2958      GenerateIntLongCompare(instruction->GetCondition(), /* is64bit */ false, locations);
2959      return;
2960    case Primitive::kPrimLong:
2961      GenerateIntLongCompare(instruction->GetCondition(), /* is64bit */ true, locations);
2962      return;
2963    case Primitive::kPrimFloat:
2964    case Primitive::kPrimDouble:
2965      GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
2966     return;
2967  }
2968}
2969
2970void InstructionCodeGeneratorMIPS64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2971  DCHECK(instruction->IsDiv() || instruction->IsRem());
2972  Primitive::Type type = instruction->GetResultType();
2973
2974  LocationSummary* locations = instruction->GetLocations();
2975  Location second = locations->InAt(1);
2976  DCHECK(second.IsConstant());
2977
2978  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
2979  GpuRegister dividend = locations->InAt(0).AsRegister<GpuRegister>();
2980  int64_t imm = Int64FromConstant(second.GetConstant());
2981  DCHECK(imm == 1 || imm == -1);
2982
2983  if (instruction->IsRem()) {
2984    __ Move(out, ZERO);
2985  } else {
2986    if (imm == -1) {
2987      if (type == Primitive::kPrimInt) {
2988        __ Subu(out, ZERO, dividend);
2989      } else {
2990        DCHECK_EQ(type, Primitive::kPrimLong);
2991        __ Dsubu(out, ZERO, dividend);
2992      }
2993    } else if (out != dividend) {
2994      __ Move(out, dividend);
2995    }
2996  }
2997}
2998
2999void InstructionCodeGeneratorMIPS64::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
3000  DCHECK(instruction->IsDiv() || instruction->IsRem());
3001  Primitive::Type type = instruction->GetResultType();
3002
3003  LocationSummary* locations = instruction->GetLocations();
3004  Location second = locations->InAt(1);
3005  DCHECK(second.IsConstant());
3006
3007  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
3008  GpuRegister dividend = locations->InAt(0).AsRegister<GpuRegister>();
3009  int64_t imm = Int64FromConstant(second.GetConstant());
3010  uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm));
3011  int ctz_imm = CTZ(abs_imm);
3012
3013  if (instruction->IsDiv()) {
3014    if (type == Primitive::kPrimInt) {
3015      if (ctz_imm == 1) {
3016        // Fast path for division by +/-2, which is very common.
3017        __ Srl(TMP, dividend, 31);
3018      } else {
3019        __ Sra(TMP, dividend, 31);
3020        __ Srl(TMP, TMP, 32 - ctz_imm);
3021      }
3022      __ Addu(out, dividend, TMP);
3023      __ Sra(out, out, ctz_imm);
3024      if (imm < 0) {
3025        __ Subu(out, ZERO, out);
3026      }
3027    } else {
3028      DCHECK_EQ(type, Primitive::kPrimLong);
3029      if (ctz_imm == 1) {
3030        // Fast path for division by +/-2, which is very common.
3031        __ Dsrl32(TMP, dividend, 31);
3032      } else {
3033        __ Dsra32(TMP, dividend, 31);
3034        if (ctz_imm > 32) {
3035          __ Dsrl(TMP, TMP, 64 - ctz_imm);
3036        } else {
3037          __ Dsrl32(TMP, TMP, 32 - ctz_imm);
3038        }
3039      }
3040      __ Daddu(out, dividend, TMP);
3041      if (ctz_imm < 32) {
3042        __ Dsra(out, out, ctz_imm);
3043      } else {
3044        __ Dsra32(out, out, ctz_imm - 32);
3045      }
3046      if (imm < 0) {
3047        __ Dsubu(out, ZERO, out);
3048      }
3049    }
3050  } else {
3051    if (type == Primitive::kPrimInt) {
3052      if (ctz_imm == 1) {
3053        // Fast path for modulo +/-2, which is very common.
3054        __ Sra(TMP, dividend, 31);
3055        __ Subu(out, dividend, TMP);
3056        __ Andi(out, out, 1);
3057        __ Addu(out, out, TMP);
3058      } else {
3059        __ Sra(TMP, dividend, 31);
3060        __ Srl(TMP, TMP, 32 - ctz_imm);
3061        __ Addu(out, dividend, TMP);
3062        if (IsUint<16>(abs_imm - 1)) {
3063          __ Andi(out, out, abs_imm - 1);
3064        } else {
3065          __ Sll(out, out, 32 - ctz_imm);
3066          __ Srl(out, out, 32 - ctz_imm);
3067        }
3068        __ Subu(out, out, TMP);
3069      }
3070    } else {
3071      DCHECK_EQ(type, Primitive::kPrimLong);
3072      if (ctz_imm == 1) {
3073        // Fast path for modulo +/-2, which is very common.
3074        __ Dsra32(TMP, dividend, 31);
3075        __ Dsubu(out, dividend, TMP);
3076        __ Andi(out, out, 1);
3077        __ Daddu(out, out, TMP);
3078      } else {
3079        __ Dsra32(TMP, dividend, 31);
3080        if (ctz_imm > 32) {
3081          __ Dsrl(TMP, TMP, 64 - ctz_imm);
3082        } else {
3083          __ Dsrl32(TMP, TMP, 32 - ctz_imm);
3084        }
3085        __ Daddu(out, dividend, TMP);
3086        if (IsUint<16>(abs_imm - 1)) {
3087          __ Andi(out, out, abs_imm - 1);
3088        } else {
3089          if (ctz_imm > 32) {
3090            __ Dsll(out, out, 64 - ctz_imm);
3091            __ Dsrl(out, out, 64 - ctz_imm);
3092          } else {
3093            __ Dsll32(out, out, 32 - ctz_imm);
3094            __ Dsrl32(out, out, 32 - ctz_imm);
3095          }
3096        }
3097        __ Dsubu(out, out, TMP);
3098      }
3099    }
3100  }
3101}
3102
3103void InstructionCodeGeneratorMIPS64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3104  DCHECK(instruction->IsDiv() || instruction->IsRem());
3105
3106  LocationSummary* locations = instruction->GetLocations();
3107  Location second = locations->InAt(1);
3108  DCHECK(second.IsConstant());
3109
3110  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
3111  GpuRegister dividend = locations->InAt(0).AsRegister<GpuRegister>();
3112  int64_t imm = Int64FromConstant(second.GetConstant());
3113
3114  Primitive::Type type = instruction->GetResultType();
3115  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << type;
3116
3117  int64_t magic;
3118  int shift;
3119  CalculateMagicAndShiftForDivRem(imm,
3120                                  (type == Primitive::kPrimLong),
3121                                  &magic,
3122                                  &shift);
3123
3124  if (type == Primitive::kPrimInt) {
3125    __ LoadConst32(TMP, magic);
3126    __ MuhR6(TMP, dividend, TMP);
3127
3128    if (imm > 0 && magic < 0) {
3129      __ Addu(TMP, TMP, dividend);
3130    } else if (imm < 0 && magic > 0) {
3131      __ Subu(TMP, TMP, dividend);
3132    }
3133
3134    if (shift != 0) {
3135      __ Sra(TMP, TMP, shift);
3136    }
3137
3138    if (instruction->IsDiv()) {
3139      __ Sra(out, TMP, 31);
3140      __ Subu(out, TMP, out);
3141    } else {
3142      __ Sra(AT, TMP, 31);
3143      __ Subu(AT, TMP, AT);
3144      __ LoadConst32(TMP, imm);
3145      __ MulR6(TMP, AT, TMP);
3146      __ Subu(out, dividend, TMP);
3147    }
3148  } else {
3149    __ LoadConst64(TMP, magic);
3150    __ Dmuh(TMP, dividend, TMP);
3151
3152    if (imm > 0 && magic < 0) {
3153      __ Daddu(TMP, TMP, dividend);
3154    } else if (imm < 0 && magic > 0) {
3155      __ Dsubu(TMP, TMP, dividend);
3156    }
3157
3158    if (shift >= 32) {
3159      __ Dsra32(TMP, TMP, shift - 32);
3160    } else if (shift > 0) {
3161      __ Dsra(TMP, TMP, shift);
3162    }
3163
3164    if (instruction->IsDiv()) {
3165      __ Dsra32(out, TMP, 31);
3166      __ Dsubu(out, TMP, out);
3167    } else {
3168      __ Dsra32(AT, TMP, 31);
3169      __ Dsubu(AT, TMP, AT);
3170      __ LoadConst64(TMP, imm);
3171      __ Dmul(TMP, AT, TMP);
3172      __ Dsubu(out, dividend, TMP);
3173    }
3174  }
3175}
3176
3177void InstructionCodeGeneratorMIPS64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3178  DCHECK(instruction->IsDiv() || instruction->IsRem());
3179  Primitive::Type type = instruction->GetResultType();
3180  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << type;
3181
3182  LocationSummary* locations = instruction->GetLocations();
3183  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
3184  Location second = locations->InAt(1);
3185
3186  if (second.IsConstant()) {
3187    int64_t imm = Int64FromConstant(second.GetConstant());
3188    if (imm == 0) {
3189      // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3190    } else if (imm == 1 || imm == -1) {
3191      DivRemOneOrMinusOne(instruction);
3192    } else if (IsPowerOfTwo(AbsOrMin(imm))) {
3193      DivRemByPowerOfTwo(instruction);
3194    } else {
3195      DCHECK(imm <= -2 || imm >= 2);
3196      GenerateDivRemWithAnyConstant(instruction);
3197    }
3198  } else {
3199    GpuRegister dividend = locations->InAt(0).AsRegister<GpuRegister>();
3200    GpuRegister divisor = second.AsRegister<GpuRegister>();
3201    if (instruction->IsDiv()) {
3202      if (type == Primitive::kPrimInt)
3203        __ DivR6(out, dividend, divisor);
3204      else
3205        __ Ddiv(out, dividend, divisor);
3206    } else {
3207      if (type == Primitive::kPrimInt)
3208        __ ModR6(out, dividend, divisor);
3209      else
3210        __ Dmod(out, dividend, divisor);
3211    }
3212  }
3213}
3214
3215void LocationsBuilderMIPS64::VisitDiv(HDiv* div) {
3216  LocationSummary* locations =
3217      new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
3218  switch (div->GetResultType()) {
3219    case Primitive::kPrimInt:
3220    case Primitive::kPrimLong:
3221      locations->SetInAt(0, Location::RequiresRegister());
3222      locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
3223      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3224      break;
3225
3226    case Primitive::kPrimFloat:
3227    case Primitive::kPrimDouble:
3228      locations->SetInAt(0, Location::RequiresFpuRegister());
3229      locations->SetInAt(1, Location::RequiresFpuRegister());
3230      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3231      break;
3232
3233    default:
3234      LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3235  }
3236}
3237
3238void InstructionCodeGeneratorMIPS64::VisitDiv(HDiv* instruction) {
3239  Primitive::Type type = instruction->GetType();
3240  LocationSummary* locations = instruction->GetLocations();
3241
3242  switch (type) {
3243    case Primitive::kPrimInt:
3244    case Primitive::kPrimLong:
3245      GenerateDivRemIntegral(instruction);
3246      break;
3247    case Primitive::kPrimFloat:
3248    case Primitive::kPrimDouble: {
3249      FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
3250      FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
3251      FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
3252      if (type == Primitive::kPrimFloat)
3253        __ DivS(dst, lhs, rhs);
3254      else
3255        __ DivD(dst, lhs, rhs);
3256      break;
3257    }
3258    default:
3259      LOG(FATAL) << "Unexpected div type " << type;
3260  }
3261}
3262
3263void LocationsBuilderMIPS64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3264  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
3265  locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3266}
3267
3268void InstructionCodeGeneratorMIPS64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
3269  SlowPathCodeMIPS64* slow_path =
3270      new (GetGraph()->GetArena()) DivZeroCheckSlowPathMIPS64(instruction);
3271  codegen_->AddSlowPath(slow_path);
3272  Location value = instruction->GetLocations()->InAt(0);
3273
3274  Primitive::Type type = instruction->GetType();
3275
3276  if (!Primitive::IsIntegralType(type)) {
3277    LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
3278    return;
3279  }
3280
3281  if (value.IsConstant()) {
3282    int64_t divisor = codegen_->GetInt64ValueOf(value.GetConstant()->AsConstant());
3283    if (divisor == 0) {
3284      __ Bc(slow_path->GetEntryLabel());
3285    } else {
3286      // A division by a non-null constant is valid. We don't need to perform
3287      // any check, so simply fall through.
3288    }
3289  } else {
3290    __ Beqzc(value.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
3291  }
3292}
3293
3294void LocationsBuilderMIPS64::VisitDoubleConstant(HDoubleConstant* constant) {
3295  LocationSummary* locations =
3296      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3297  locations->SetOut(Location::ConstantLocation(constant));
3298}
3299
3300void InstructionCodeGeneratorMIPS64::VisitDoubleConstant(HDoubleConstant* cst ATTRIBUTE_UNUSED) {
3301  // Will be generated at use site.
3302}
3303
3304void LocationsBuilderMIPS64::VisitExit(HExit* exit) {
3305  exit->SetLocations(nullptr);
3306}
3307
3308void InstructionCodeGeneratorMIPS64::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
3309}
3310
3311void LocationsBuilderMIPS64::VisitFloatConstant(HFloatConstant* constant) {
3312  LocationSummary* locations =
3313      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3314  locations->SetOut(Location::ConstantLocation(constant));
3315}
3316
3317void InstructionCodeGeneratorMIPS64::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
3318  // Will be generated at use site.
3319}
3320
3321void InstructionCodeGeneratorMIPS64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
3322  DCHECK(!successor->IsExitBlock());
3323  HBasicBlock* block = got->GetBlock();
3324  HInstruction* previous = got->GetPrevious();
3325  HLoopInformation* info = block->GetLoopInformation();
3326
3327  if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
3328    codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
3329    GenerateSuspendCheck(info->GetSuspendCheck(), successor);
3330    return;
3331  }
3332  if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
3333    GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
3334  }
3335  if (!codegen_->GoesToNextBlock(block, successor)) {
3336    __ Bc(codegen_->GetLabelOf(successor));
3337  }
3338}
3339
3340void LocationsBuilderMIPS64::VisitGoto(HGoto* got) {
3341  got->SetLocations(nullptr);
3342}
3343
3344void InstructionCodeGeneratorMIPS64::VisitGoto(HGoto* got) {
3345  HandleGoto(got, got->GetSuccessor());
3346}
3347
3348void LocationsBuilderMIPS64::VisitTryBoundary(HTryBoundary* try_boundary) {
3349  try_boundary->SetLocations(nullptr);
3350}
3351
3352void InstructionCodeGeneratorMIPS64::VisitTryBoundary(HTryBoundary* try_boundary) {
3353  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
3354  if (!successor->IsExitBlock()) {
3355    HandleGoto(try_boundary, successor);
3356  }
3357}
3358
3359void InstructionCodeGeneratorMIPS64::GenerateIntLongCompare(IfCondition cond,
3360                                                            bool is64bit,
3361                                                            LocationSummary* locations) {
3362  GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
3363  GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
3364  Location rhs_location = locations->InAt(1);
3365  GpuRegister rhs_reg = ZERO;
3366  int64_t rhs_imm = 0;
3367  bool use_imm = rhs_location.IsConstant();
3368  if (use_imm) {
3369    if (is64bit) {
3370      rhs_imm = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant());
3371    } else {
3372      rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
3373    }
3374  } else {
3375    rhs_reg = rhs_location.AsRegister<GpuRegister>();
3376  }
3377  int64_t rhs_imm_plus_one = rhs_imm + UINT64_C(1);
3378
3379  switch (cond) {
3380    case kCondEQ:
3381    case kCondNE:
3382      if (use_imm && IsInt<16>(-rhs_imm)) {
3383        if (rhs_imm == 0) {
3384          if (cond == kCondEQ) {
3385            __ Sltiu(dst, lhs, 1);
3386          } else {
3387            __ Sltu(dst, ZERO, lhs);
3388          }
3389        } else {
3390          if (is64bit) {
3391            __ Daddiu(dst, lhs, -rhs_imm);
3392          } else {
3393            __ Addiu(dst, lhs, -rhs_imm);
3394          }
3395          if (cond == kCondEQ) {
3396            __ Sltiu(dst, dst, 1);
3397          } else {
3398            __ Sltu(dst, ZERO, dst);
3399          }
3400        }
3401      } else {
3402        if (use_imm && IsUint<16>(rhs_imm)) {
3403          __ Xori(dst, lhs, rhs_imm);
3404        } else {
3405          if (use_imm) {
3406            rhs_reg = TMP;
3407            __ LoadConst64(rhs_reg, rhs_imm);
3408          }
3409          __ Xor(dst, lhs, rhs_reg);
3410        }
3411        if (cond == kCondEQ) {
3412          __ Sltiu(dst, dst, 1);
3413        } else {
3414          __ Sltu(dst, ZERO, dst);
3415        }
3416      }
3417      break;
3418
3419    case kCondLT:
3420    case kCondGE:
3421      if (use_imm && IsInt<16>(rhs_imm)) {
3422        __ Slti(dst, lhs, rhs_imm);
3423      } else {
3424        if (use_imm) {
3425          rhs_reg = TMP;
3426          __ LoadConst64(rhs_reg, rhs_imm);
3427        }
3428        __ Slt(dst, lhs, rhs_reg);
3429      }
3430      if (cond == kCondGE) {
3431        // Simulate lhs >= rhs via !(lhs < rhs) since there's
3432        // only the slt instruction but no sge.
3433        __ Xori(dst, dst, 1);
3434      }
3435      break;
3436
3437    case kCondLE:
3438    case kCondGT:
3439      if (use_imm && IsInt<16>(rhs_imm_plus_one)) {
3440        // Simulate lhs <= rhs via lhs < rhs + 1.
3441        __ Slti(dst, lhs, rhs_imm_plus_one);
3442        if (cond == kCondGT) {
3443          // Simulate lhs > rhs via !(lhs <= rhs) since there's
3444          // only the slti instruction but no sgti.
3445          __ Xori(dst, dst, 1);
3446        }
3447      } else {
3448        if (use_imm) {
3449          rhs_reg = TMP;
3450          __ LoadConst64(rhs_reg, rhs_imm);
3451        }
3452        __ Slt(dst, rhs_reg, lhs);
3453        if (cond == kCondLE) {
3454          // Simulate lhs <= rhs via !(rhs < lhs) since there's
3455          // only the slt instruction but no sle.
3456          __ Xori(dst, dst, 1);
3457        }
3458      }
3459      break;
3460
3461    case kCondB:
3462    case kCondAE:
3463      if (use_imm && IsInt<16>(rhs_imm)) {
3464        // Sltiu sign-extends its 16-bit immediate operand before
3465        // the comparison and thus lets us compare directly with
3466        // unsigned values in the ranges [0, 0x7fff] and
3467        // [0x[ffffffff]ffff8000, 0x[ffffffff]ffffffff].
3468        __ Sltiu(dst, lhs, rhs_imm);
3469      } else {
3470        if (use_imm) {
3471          rhs_reg = TMP;
3472          __ LoadConst64(rhs_reg, rhs_imm);
3473        }
3474        __ Sltu(dst, lhs, rhs_reg);
3475      }
3476      if (cond == kCondAE) {
3477        // Simulate lhs >= rhs via !(lhs < rhs) since there's
3478        // only the sltu instruction but no sgeu.
3479        __ Xori(dst, dst, 1);
3480      }
3481      break;
3482
3483    case kCondBE:
3484    case kCondA:
3485      if (use_imm && (rhs_imm_plus_one != 0) && IsInt<16>(rhs_imm_plus_one)) {
3486        // Simulate lhs <= rhs via lhs < rhs + 1.
3487        // Note that this only works if rhs + 1 does not overflow
3488        // to 0, hence the check above.
3489        // Sltiu sign-extends its 16-bit immediate operand before
3490        // the comparison and thus lets us compare directly with
3491        // unsigned values in the ranges [0, 0x7fff] and
3492        // [0x[ffffffff]ffff8000, 0x[ffffffff]ffffffff].
3493        __ Sltiu(dst, lhs, rhs_imm_plus_one);
3494        if (cond == kCondA) {
3495          // Simulate lhs > rhs via !(lhs <= rhs) since there's
3496          // only the sltiu instruction but no sgtiu.
3497          __ Xori(dst, dst, 1);
3498        }
3499      } else {
3500        if (use_imm) {
3501          rhs_reg = TMP;
3502          __ LoadConst64(rhs_reg, rhs_imm);
3503        }
3504        __ Sltu(dst, rhs_reg, lhs);
3505        if (cond == kCondBE) {
3506          // Simulate lhs <= rhs via !(rhs < lhs) since there's
3507          // only the sltu instruction but no sleu.
3508          __ Xori(dst, dst, 1);
3509        }
3510      }
3511      break;
3512  }
3513}
3514
3515void InstructionCodeGeneratorMIPS64::GenerateIntLongCompareAndBranch(IfCondition cond,
3516                                                                     bool is64bit,
3517                                                                     LocationSummary* locations,
3518                                                                     Mips64Label* label) {
3519  GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
3520  Location rhs_location = locations->InAt(1);
3521  GpuRegister rhs_reg = ZERO;
3522  int64_t rhs_imm = 0;
3523  bool use_imm = rhs_location.IsConstant();
3524  if (use_imm) {
3525    if (is64bit) {
3526      rhs_imm = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant());
3527    } else {
3528      rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
3529    }
3530  } else {
3531    rhs_reg = rhs_location.AsRegister<GpuRegister>();
3532  }
3533
3534  if (use_imm && rhs_imm == 0) {
3535    switch (cond) {
3536      case kCondEQ:
3537      case kCondBE:  // <= 0 if zero
3538        __ Beqzc(lhs, label);
3539        break;
3540      case kCondNE:
3541      case kCondA:  // > 0 if non-zero
3542        __ Bnezc(lhs, label);
3543        break;
3544      case kCondLT:
3545        __ Bltzc(lhs, label);
3546        break;
3547      case kCondGE:
3548        __ Bgezc(lhs, label);
3549        break;
3550      case kCondLE:
3551        __ Blezc(lhs, label);
3552        break;
3553      case kCondGT:
3554        __ Bgtzc(lhs, label);
3555        break;
3556      case kCondB:  // always false
3557        break;
3558      case kCondAE:  // always true
3559        __ Bc(label);
3560        break;
3561    }
3562  } else {
3563    if (use_imm) {
3564      rhs_reg = TMP;
3565      __ LoadConst64(rhs_reg, rhs_imm);
3566    }
3567    switch (cond) {
3568      case kCondEQ:
3569        __ Beqc(lhs, rhs_reg, label);
3570        break;
3571      case kCondNE:
3572        __ Bnec(lhs, rhs_reg, label);
3573        break;
3574      case kCondLT:
3575        __ Bltc(lhs, rhs_reg, label);
3576        break;
3577      case kCondGE:
3578        __ Bgec(lhs, rhs_reg, label);
3579        break;
3580      case kCondLE:
3581        __ Bgec(rhs_reg, lhs, label);
3582        break;
3583      case kCondGT:
3584        __ Bltc(rhs_reg, lhs, label);
3585        break;
3586      case kCondB:
3587        __ Bltuc(lhs, rhs_reg, label);
3588        break;
3589      case kCondAE:
3590        __ Bgeuc(lhs, rhs_reg, label);
3591        break;
3592      case kCondBE:
3593        __ Bgeuc(rhs_reg, lhs, label);
3594        break;
3595      case kCondA:
3596        __ Bltuc(rhs_reg, lhs, label);
3597        break;
3598    }
3599  }
3600}
3601
3602void InstructionCodeGeneratorMIPS64::GenerateFpCompare(IfCondition cond,
3603                                                       bool gt_bias,
3604                                                       Primitive::Type type,
3605                                                       LocationSummary* locations) {
3606  GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
3607  FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
3608  FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
3609  if (type == Primitive::kPrimFloat) {
3610    switch (cond) {
3611      case kCondEQ:
3612        __ CmpEqS(FTMP, lhs, rhs);
3613        __ Mfc1(dst, FTMP);
3614        __ Andi(dst, dst, 1);
3615        break;
3616      case kCondNE:
3617        __ CmpEqS(FTMP, lhs, rhs);
3618        __ Mfc1(dst, FTMP);
3619        __ Addiu(dst, dst, 1);
3620        break;
3621      case kCondLT:
3622        if (gt_bias) {
3623          __ CmpLtS(FTMP, lhs, rhs);
3624        } else {
3625          __ CmpUltS(FTMP, lhs, rhs);
3626        }
3627        __ Mfc1(dst, FTMP);
3628        __ Andi(dst, dst, 1);
3629        break;
3630      case kCondLE:
3631        if (gt_bias) {
3632          __ CmpLeS(FTMP, lhs, rhs);
3633        } else {
3634          __ CmpUleS(FTMP, lhs, rhs);
3635        }
3636        __ Mfc1(dst, FTMP);
3637        __ Andi(dst, dst, 1);
3638        break;
3639      case kCondGT:
3640        if (gt_bias) {
3641          __ CmpUltS(FTMP, rhs, lhs);
3642        } else {
3643          __ CmpLtS(FTMP, rhs, lhs);
3644        }
3645        __ Mfc1(dst, FTMP);
3646        __ Andi(dst, dst, 1);
3647        break;
3648      case kCondGE:
3649        if (gt_bias) {
3650          __ CmpUleS(FTMP, rhs, lhs);
3651        } else {
3652          __ CmpLeS(FTMP, rhs, lhs);
3653        }
3654        __ Mfc1(dst, FTMP);
3655        __ Andi(dst, dst, 1);
3656        break;
3657      default:
3658        LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3659        UNREACHABLE();
3660    }
3661  } else {
3662    DCHECK_EQ(type, Primitive::kPrimDouble);
3663    switch (cond) {
3664      case kCondEQ:
3665        __ CmpEqD(FTMP, lhs, rhs);
3666        __ Mfc1(dst, FTMP);
3667        __ Andi(dst, dst, 1);
3668        break;
3669      case kCondNE:
3670        __ CmpEqD(FTMP, lhs, rhs);
3671        __ Mfc1(dst, FTMP);
3672        __ Addiu(dst, dst, 1);
3673        break;
3674      case kCondLT:
3675        if (gt_bias) {
3676          __ CmpLtD(FTMP, lhs, rhs);
3677        } else {
3678          __ CmpUltD(FTMP, lhs, rhs);
3679        }
3680        __ Mfc1(dst, FTMP);
3681        __ Andi(dst, dst, 1);
3682        break;
3683      case kCondLE:
3684        if (gt_bias) {
3685          __ CmpLeD(FTMP, lhs, rhs);
3686        } else {
3687          __ CmpUleD(FTMP, lhs, rhs);
3688        }
3689        __ Mfc1(dst, FTMP);
3690        __ Andi(dst, dst, 1);
3691        break;
3692      case kCondGT:
3693        if (gt_bias) {
3694          __ CmpUltD(FTMP, rhs, lhs);
3695        } else {
3696          __ CmpLtD(FTMP, rhs, lhs);
3697        }
3698        __ Mfc1(dst, FTMP);
3699        __ Andi(dst, dst, 1);
3700        break;
3701      case kCondGE:
3702        if (gt_bias) {
3703          __ CmpUleD(FTMP, rhs, lhs);
3704        } else {
3705          __ CmpLeD(FTMP, rhs, lhs);
3706        }
3707        __ Mfc1(dst, FTMP);
3708        __ Andi(dst, dst, 1);
3709        break;
3710      default:
3711        LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3712        UNREACHABLE();
3713    }
3714  }
3715}
3716
3717void InstructionCodeGeneratorMIPS64::GenerateFpCompareAndBranch(IfCondition cond,
3718                                                                bool gt_bias,
3719                                                                Primitive::Type type,
3720                                                                LocationSummary* locations,
3721                                                                Mips64Label* label) {
3722  FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
3723  FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
3724  if (type == Primitive::kPrimFloat) {
3725    switch (cond) {
3726      case kCondEQ:
3727        __ CmpEqS(FTMP, lhs, rhs);
3728        __ Bc1nez(FTMP, label);
3729        break;
3730      case kCondNE:
3731        __ CmpEqS(FTMP, lhs, rhs);
3732        __ Bc1eqz(FTMP, label);
3733        break;
3734      case kCondLT:
3735        if (gt_bias) {
3736          __ CmpLtS(FTMP, lhs, rhs);
3737        } else {
3738          __ CmpUltS(FTMP, lhs, rhs);
3739        }
3740        __ Bc1nez(FTMP, label);
3741        break;
3742      case kCondLE:
3743        if (gt_bias) {
3744          __ CmpLeS(FTMP, lhs, rhs);
3745        } else {
3746          __ CmpUleS(FTMP, lhs, rhs);
3747        }
3748        __ Bc1nez(FTMP, label);
3749        break;
3750      case kCondGT:
3751        if (gt_bias) {
3752          __ CmpUltS(FTMP, rhs, lhs);
3753        } else {
3754          __ CmpLtS(FTMP, rhs, lhs);
3755        }
3756        __ Bc1nez(FTMP, label);
3757        break;
3758      case kCondGE:
3759        if (gt_bias) {
3760          __ CmpUleS(FTMP, rhs, lhs);
3761        } else {
3762          __ CmpLeS(FTMP, rhs, lhs);
3763        }
3764        __ Bc1nez(FTMP, label);
3765        break;
3766      default:
3767        LOG(FATAL) << "Unexpected non-floating-point condition";
3768    }
3769  } else {
3770    DCHECK_EQ(type, Primitive::kPrimDouble);
3771    switch (cond) {
3772      case kCondEQ:
3773        __ CmpEqD(FTMP, lhs, rhs);
3774        __ Bc1nez(FTMP, label);
3775        break;
3776      case kCondNE:
3777        __ CmpEqD(FTMP, lhs, rhs);
3778        __ Bc1eqz(FTMP, label);
3779        break;
3780      case kCondLT:
3781        if (gt_bias) {
3782          __ CmpLtD(FTMP, lhs, rhs);
3783        } else {
3784          __ CmpUltD(FTMP, lhs, rhs);
3785        }
3786        __ Bc1nez(FTMP, label);
3787        break;
3788      case kCondLE:
3789        if (gt_bias) {
3790          __ CmpLeD(FTMP, lhs, rhs);
3791        } else {
3792          __ CmpUleD(FTMP, lhs, rhs);
3793        }
3794        __ Bc1nez(FTMP, label);
3795        break;
3796      case kCondGT:
3797        if (gt_bias) {
3798          __ CmpUltD(FTMP, rhs, lhs);
3799        } else {
3800          __ CmpLtD(FTMP, rhs, lhs);
3801        }
3802        __ Bc1nez(FTMP, label);
3803        break;
3804      case kCondGE:
3805        if (gt_bias) {
3806          __ CmpUleD(FTMP, rhs, lhs);
3807        } else {
3808          __ CmpLeD(FTMP, rhs, lhs);
3809        }
3810        __ Bc1nez(FTMP, label);
3811        break;
3812      default:
3813        LOG(FATAL) << "Unexpected non-floating-point condition";
3814    }
3815  }
3816}
3817
3818void InstructionCodeGeneratorMIPS64::GenerateTestAndBranch(HInstruction* instruction,
3819                                                           size_t condition_input_index,
3820                                                           Mips64Label* true_target,
3821                                                           Mips64Label* false_target) {
3822  HInstruction* cond = instruction->InputAt(condition_input_index);
3823
3824  if (true_target == nullptr && false_target == nullptr) {
3825    // Nothing to do. The code always falls through.
3826    return;
3827  } else if (cond->IsIntConstant()) {
3828    // Constant condition, statically compared against "true" (integer value 1).
3829    if (cond->AsIntConstant()->IsTrue()) {
3830      if (true_target != nullptr) {
3831        __ Bc(true_target);
3832      }
3833    } else {
3834      DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
3835      if (false_target != nullptr) {
3836        __ Bc(false_target);
3837      }
3838    }
3839    return;
3840  }
3841
3842  // The following code generates these patterns:
3843  //  (1) true_target == nullptr && false_target != nullptr
3844  //        - opposite condition true => branch to false_target
3845  //  (2) true_target != nullptr && false_target == nullptr
3846  //        - condition true => branch to true_target
3847  //  (3) true_target != nullptr && false_target != nullptr
3848  //        - condition true => branch to true_target
3849  //        - branch to false_target
3850  if (IsBooleanValueOrMaterializedCondition(cond)) {
3851    // The condition instruction has been materialized, compare the output to 0.
3852    Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
3853    DCHECK(cond_val.IsRegister());
3854    if (true_target == nullptr) {
3855      __ Beqzc(cond_val.AsRegister<GpuRegister>(), false_target);
3856    } else {
3857      __ Bnezc(cond_val.AsRegister<GpuRegister>(), true_target);
3858    }
3859  } else {
3860    // The condition instruction has not been materialized, use its inputs as
3861    // the comparison and its condition as the branch condition.
3862    HCondition* condition = cond->AsCondition();
3863    Primitive::Type type = condition->InputAt(0)->GetType();
3864    LocationSummary* locations = cond->GetLocations();
3865    IfCondition if_cond = condition->GetCondition();
3866    Mips64Label* branch_target = true_target;
3867
3868    if (true_target == nullptr) {
3869      if_cond = condition->GetOppositeCondition();
3870      branch_target = false_target;
3871    }
3872
3873    switch (type) {
3874      default:
3875        GenerateIntLongCompareAndBranch(if_cond, /* is64bit */ false, locations, branch_target);
3876        break;
3877      case Primitive::kPrimLong:
3878        GenerateIntLongCompareAndBranch(if_cond, /* is64bit */ true, locations, branch_target);
3879        break;
3880      case Primitive::kPrimFloat:
3881      case Primitive::kPrimDouble:
3882        GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
3883        break;
3884    }
3885  }
3886
3887  // If neither branch falls through (case 3), the conditional branch to `true_target`
3888  // was already emitted (case 2) and we need to emit a jump to `false_target`.
3889  if (true_target != nullptr && false_target != nullptr) {
3890    __ Bc(false_target);
3891  }
3892}
3893
3894void LocationsBuilderMIPS64::VisitIf(HIf* if_instr) {
3895  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
3896  if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
3897    locations->SetInAt(0, Location::RequiresRegister());
3898  }
3899}
3900
3901void InstructionCodeGeneratorMIPS64::VisitIf(HIf* if_instr) {
3902  HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
3903  HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
3904  Mips64Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
3905      nullptr : codegen_->GetLabelOf(true_successor);
3906  Mips64Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
3907      nullptr : codegen_->GetLabelOf(false_successor);
3908  GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
3909}
3910
3911void LocationsBuilderMIPS64::VisitDeoptimize(HDeoptimize* deoptimize) {
3912  LocationSummary* locations = new (GetGraph()->GetArena())
3913      LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
3914  InvokeRuntimeCallingConvention calling_convention;
3915  RegisterSet caller_saves = RegisterSet::Empty();
3916  caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3917  locations->SetCustomSlowPathCallerSaves(caller_saves);
3918  if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
3919    locations->SetInAt(0, Location::RequiresRegister());
3920  }
3921}
3922
3923void InstructionCodeGeneratorMIPS64::VisitDeoptimize(HDeoptimize* deoptimize) {
3924  SlowPathCodeMIPS64* slow_path =
3925      deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathMIPS64>(deoptimize);
3926  GenerateTestAndBranch(deoptimize,
3927                        /* condition_input_index */ 0,
3928                        slow_path->GetEntryLabel(),
3929                        /* false_target */ nullptr);
3930}
3931
3932void LocationsBuilderMIPS64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
3933  LocationSummary* locations = new (GetGraph()->GetArena())
3934      LocationSummary(flag, LocationSummary::kNoCall);
3935  locations->SetOut(Location::RequiresRegister());
3936}
3937
3938void InstructionCodeGeneratorMIPS64::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
3939  __ LoadFromOffset(kLoadWord,
3940                    flag->GetLocations()->Out().AsRegister<GpuRegister>(),
3941                    SP,
3942                    codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
3943}
3944
3945void LocationsBuilderMIPS64::VisitSelect(HSelect* select) {
3946  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
3947  if (Primitive::IsFloatingPointType(select->GetType())) {
3948    locations->SetInAt(0, Location::RequiresFpuRegister());
3949    locations->SetInAt(1, Location::RequiresFpuRegister());
3950  } else {
3951    locations->SetInAt(0, Location::RequiresRegister());
3952    locations->SetInAt(1, Location::RequiresRegister());
3953  }
3954  if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
3955    locations->SetInAt(2, Location::RequiresRegister());
3956  }
3957  locations->SetOut(Location::SameAsFirstInput());
3958}
3959
3960void InstructionCodeGeneratorMIPS64::VisitSelect(HSelect* select) {
3961  LocationSummary* locations = select->GetLocations();
3962  Mips64Label false_target;
3963  GenerateTestAndBranch(select,
3964                        /* condition_input_index */ 2,
3965                        /* true_target */ nullptr,
3966                        &false_target);
3967  codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
3968  __ Bind(&false_target);
3969}
3970
3971void LocationsBuilderMIPS64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
3972  new (GetGraph()->GetArena()) LocationSummary(info);
3973}
3974
3975void InstructionCodeGeneratorMIPS64::VisitNativeDebugInfo(HNativeDebugInfo*) {
3976  // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
3977}
3978
3979void CodeGeneratorMIPS64::GenerateNop() {
3980  __ Nop();
3981}
3982
3983void LocationsBuilderMIPS64::HandleFieldGet(HInstruction* instruction,
3984                                            const FieldInfo& field_info) {
3985  Primitive::Type field_type = field_info.GetFieldType();
3986  bool object_field_get_with_read_barrier =
3987      kEmitCompilerReadBarrier && (field_type == Primitive::kPrimNot);
3988  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3989      instruction,
3990      object_field_get_with_read_barrier
3991          ? LocationSummary::kCallOnSlowPath
3992          : LocationSummary::kNoCall);
3993  locations->SetInAt(0, Location::RequiresRegister());
3994  if (Primitive::IsFloatingPointType(instruction->GetType())) {
3995    locations->SetOut(Location::RequiresFpuRegister());
3996  } else {
3997    // The output overlaps in the case of an object field get with
3998    // read barriers enabled: we do not want the move to overwrite the
3999    // object's location, as we need it to emit the read barrier.
4000    locations->SetOut(Location::RequiresRegister(),
4001                      object_field_get_with_read_barrier
4002                          ? Location::kOutputOverlap
4003                          : Location::kNoOutputOverlap);
4004  }
4005  if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
4006    // We need a temporary register for the read barrier marking slow
4007    // path in CodeGeneratorMIPS64::GenerateFieldLoadWithBakerReadBarrier.
4008    locations->AddTemp(Location::RequiresRegister());
4009  }
4010}
4011
4012void InstructionCodeGeneratorMIPS64::HandleFieldGet(HInstruction* instruction,
4013                                                    const FieldInfo& field_info) {
4014  Primitive::Type type = field_info.GetFieldType();
4015  LocationSummary* locations = instruction->GetLocations();
4016  Location obj_loc = locations->InAt(0);
4017  GpuRegister obj = obj_loc.AsRegister<GpuRegister>();
4018  Location dst_loc = locations->Out();
4019  LoadOperandType load_type = kLoadUnsignedByte;
4020  bool is_volatile = field_info.IsVolatile();
4021  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4022  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
4023
4024  switch (type) {
4025    case Primitive::kPrimBoolean:
4026      load_type = kLoadUnsignedByte;
4027      break;
4028    case Primitive::kPrimByte:
4029      load_type = kLoadSignedByte;
4030      break;
4031    case Primitive::kPrimShort:
4032      load_type = kLoadSignedHalfword;
4033      break;
4034    case Primitive::kPrimChar:
4035      load_type = kLoadUnsignedHalfword;
4036      break;
4037    case Primitive::kPrimInt:
4038    case Primitive::kPrimFloat:
4039      load_type = kLoadWord;
4040      break;
4041    case Primitive::kPrimLong:
4042    case Primitive::kPrimDouble:
4043      load_type = kLoadDoubleword;
4044      break;
4045    case Primitive::kPrimNot:
4046      load_type = kLoadUnsignedWord;
4047      break;
4048    case Primitive::kPrimVoid:
4049      LOG(FATAL) << "Unreachable type " << type;
4050      UNREACHABLE();
4051  }
4052  if (!Primitive::IsFloatingPointType(type)) {
4053    DCHECK(dst_loc.IsRegister());
4054    GpuRegister dst = dst_loc.AsRegister<GpuRegister>();
4055    if (type == Primitive::kPrimNot) {
4056      // /* HeapReference<Object> */ dst = *(obj + offset)
4057      if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
4058        Location temp_loc = locations->GetTemp(0);
4059        // Note that a potential implicit null check is handled in this
4060        // CodeGeneratorMIPS64::GenerateFieldLoadWithBakerReadBarrier call.
4061        codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
4062                                                        dst_loc,
4063                                                        obj,
4064                                                        offset,
4065                                                        temp_loc,
4066                                                        /* needs_null_check */ true);
4067        if (is_volatile) {
4068          GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4069        }
4070      } else {
4071        __ LoadFromOffset(kLoadUnsignedWord, dst, obj, offset, null_checker);
4072        if (is_volatile) {
4073          GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4074        }
4075        // If read barriers are enabled, emit read barriers other than
4076        // Baker's using a slow path (and also unpoison the loaded
4077        // reference, if heap poisoning is enabled).
4078        codegen_->MaybeGenerateReadBarrierSlow(instruction, dst_loc, dst_loc, obj_loc, offset);
4079      }
4080    } else {
4081      __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
4082    }
4083  } else {
4084    DCHECK(dst_loc.IsFpuRegister());
4085    FpuRegister dst = dst_loc.AsFpuRegister<FpuRegister>();
4086    __ LoadFpuFromOffset(load_type, dst, obj, offset, null_checker);
4087  }
4088
4089  // Memory barriers, in the case of references, are handled in the
4090  // previous switch statement.
4091  if (is_volatile && (type != Primitive::kPrimNot)) {
4092    GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4093  }
4094}
4095
4096void LocationsBuilderMIPS64::HandleFieldSet(HInstruction* instruction,
4097                                            const FieldInfo& field_info ATTRIBUTE_UNUSED) {
4098  LocationSummary* locations =
4099      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4100  locations->SetInAt(0, Location::RequiresRegister());
4101  if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
4102    locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
4103  } else {
4104    locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
4105  }
4106}
4107
4108void InstructionCodeGeneratorMIPS64::HandleFieldSet(HInstruction* instruction,
4109                                                    const FieldInfo& field_info,
4110                                                    bool value_can_be_null) {
4111  Primitive::Type type = field_info.GetFieldType();
4112  LocationSummary* locations = instruction->GetLocations();
4113  GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>();
4114  Location value_location = locations->InAt(1);
4115  StoreOperandType store_type = kStoreByte;
4116  bool is_volatile = field_info.IsVolatile();
4117  uint32_t offset = field_info.GetFieldOffset().Uint32Value();
4118  bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1));
4119  auto null_checker = GetImplicitNullChecker(instruction, codegen_);
4120
4121  switch (type) {
4122    case Primitive::kPrimBoolean:
4123    case Primitive::kPrimByte:
4124      store_type = kStoreByte;
4125      break;
4126    case Primitive::kPrimShort:
4127    case Primitive::kPrimChar:
4128      store_type = kStoreHalfword;
4129      break;
4130    case Primitive::kPrimInt:
4131    case Primitive::kPrimFloat:
4132    case Primitive::kPrimNot:
4133      store_type = kStoreWord;
4134      break;
4135    case Primitive::kPrimLong:
4136    case Primitive::kPrimDouble:
4137      store_type = kStoreDoubleword;
4138      break;
4139    case Primitive::kPrimVoid:
4140      LOG(FATAL) << "Unreachable type " << type;
4141      UNREACHABLE();
4142  }
4143
4144  if (is_volatile) {
4145    GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4146  }
4147
4148  if (value_location.IsConstant()) {
4149    int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
4150    __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
4151  } else {
4152    if (!Primitive::IsFloatingPointType(type)) {
4153      DCHECK(value_location.IsRegister());
4154      GpuRegister src = value_location.AsRegister<GpuRegister>();
4155      if (kPoisonHeapReferences && needs_write_barrier) {
4156        // Note that in the case where `value` is a null reference,
4157        // we do not enter this block, as a null reference does not
4158        // need poisoning.
4159        DCHECK_EQ(type, Primitive::kPrimNot);
4160        __ PoisonHeapReference(TMP, src);
4161        __ StoreToOffset(store_type, TMP, obj, offset, null_checker);
4162      } else {
4163        __ StoreToOffset(store_type, src, obj, offset, null_checker);
4164      }
4165    } else {
4166      DCHECK(value_location.IsFpuRegister());
4167      FpuRegister src = value_location.AsFpuRegister<FpuRegister>();
4168      __ StoreFpuToOffset(store_type, src, obj, offset, null_checker);
4169    }
4170  }
4171
4172  if (needs_write_barrier) {
4173    DCHECK(value_location.IsRegister());
4174    GpuRegister src = value_location.AsRegister<GpuRegister>();
4175    codegen_->MarkGCCard(obj, src, value_can_be_null);
4176  }
4177
4178  if (is_volatile) {
4179    GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4180  }
4181}
4182
4183void LocationsBuilderMIPS64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4184  HandleFieldGet(instruction, instruction->GetFieldInfo());
4185}
4186
4187void InstructionCodeGeneratorMIPS64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4188  HandleFieldGet(instruction, instruction->GetFieldInfo());
4189}
4190
4191void LocationsBuilderMIPS64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4192  HandleFieldSet(instruction, instruction->GetFieldInfo());
4193}
4194
4195void InstructionCodeGeneratorMIPS64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4196  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
4197}
4198
4199void InstructionCodeGeneratorMIPS64::GenerateReferenceLoadOneRegister(
4200    HInstruction* instruction,
4201    Location out,
4202    uint32_t offset,
4203    Location maybe_temp,
4204    ReadBarrierOption read_barrier_option) {
4205  GpuRegister out_reg = out.AsRegister<GpuRegister>();
4206  if (read_barrier_option == kWithReadBarrier) {
4207    CHECK(kEmitCompilerReadBarrier);
4208    DCHECK(maybe_temp.IsRegister()) << maybe_temp;
4209    if (kUseBakerReadBarrier) {
4210      // Load with fast path based Baker's read barrier.
4211      // /* HeapReference<Object> */ out = *(out + offset)
4212      codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
4213                                                      out,
4214                                                      out_reg,
4215                                                      offset,
4216                                                      maybe_temp,
4217                                                      /* needs_null_check */ false);
4218    } else {
4219      // Load with slow path based read barrier.
4220      // Save the value of `out` into `maybe_temp` before overwriting it
4221      // in the following move operation, as we will need it for the
4222      // read barrier below.
4223      __ Move(maybe_temp.AsRegister<GpuRegister>(), out_reg);
4224      // /* HeapReference<Object> */ out = *(out + offset)
4225      __ LoadFromOffset(kLoadUnsignedWord, out_reg, out_reg, offset);
4226      codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
4227    }
4228  } else {
4229    // Plain load with no read barrier.
4230    // /* HeapReference<Object> */ out = *(out + offset)
4231    __ LoadFromOffset(kLoadUnsignedWord, out_reg, out_reg, offset);
4232    __ MaybeUnpoisonHeapReference(out_reg);
4233  }
4234}
4235
4236void InstructionCodeGeneratorMIPS64::GenerateReferenceLoadTwoRegisters(
4237    HInstruction* instruction,
4238    Location out,
4239    Location obj,
4240    uint32_t offset,
4241    Location maybe_temp,
4242    ReadBarrierOption read_barrier_option) {
4243  GpuRegister out_reg = out.AsRegister<GpuRegister>();
4244  GpuRegister obj_reg = obj.AsRegister<GpuRegister>();
4245  if (read_barrier_option == kWithReadBarrier) {
4246    CHECK(kEmitCompilerReadBarrier);
4247    if (kUseBakerReadBarrier) {
4248      DCHECK(maybe_temp.IsRegister()) << maybe_temp;
4249      // Load with fast path based Baker's read barrier.
4250      // /* HeapReference<Object> */ out = *(obj + offset)
4251      codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
4252                                                      out,
4253                                                      obj_reg,
4254                                                      offset,
4255                                                      maybe_temp,
4256                                                      /* needs_null_check */ false);
4257    } else {
4258      // Load with slow path based read barrier.
4259      // /* HeapReference<Object> */ out = *(obj + offset)
4260      __ LoadFromOffset(kLoadUnsignedWord, out_reg, obj_reg, offset);
4261      codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
4262    }
4263  } else {
4264    // Plain load with no read barrier.
4265    // /* HeapReference<Object> */ out = *(obj + offset)
4266    __ LoadFromOffset(kLoadUnsignedWord, out_reg, obj_reg, offset);
4267    __ MaybeUnpoisonHeapReference(out_reg);
4268  }
4269}
4270
4271void InstructionCodeGeneratorMIPS64::GenerateGcRootFieldLoad(
4272    HInstruction* instruction,
4273    Location root,
4274    GpuRegister obj,
4275    uint32_t offset,
4276    ReadBarrierOption read_barrier_option) {
4277  GpuRegister root_reg = root.AsRegister<GpuRegister>();
4278  if (read_barrier_option == kWithReadBarrier) {
4279    DCHECK(kEmitCompilerReadBarrier);
4280    if (kUseBakerReadBarrier) {
4281      // Fast path implementation of art::ReadBarrier::BarrierForRoot when
4282      // Baker's read barrier are used:
4283      //
4284      //   root = obj.field;
4285      //   temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
4286      //   if (temp != null) {
4287      //     root = temp(root)
4288      //   }
4289
4290      // /* GcRoot<mirror::Object> */ root = *(obj + offset)
4291      __ LoadFromOffset(kLoadUnsignedWord, root_reg, obj, offset);
4292      static_assert(
4293          sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
4294          "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
4295          "have different sizes.");
4296      static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
4297                    "art::mirror::CompressedReference<mirror::Object> and int32_t "
4298                    "have different sizes.");
4299
4300      // Slow path marking the GC root `root`.
4301      Location temp = Location::RegisterLocation(T9);
4302      SlowPathCodeMIPS64* slow_path =
4303          new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathMIPS64(
4304              instruction,
4305              root,
4306              /*entrypoint*/ temp);
4307      codegen_->AddSlowPath(slow_path);
4308
4309      // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
4310      const int32_t entry_point_offset =
4311          CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kMips64PointerSize>(root.reg() - 1);
4312      // Loading the entrypoint does not require a load acquire since it is only changed when
4313      // threads are suspended or running a checkpoint.
4314      __ LoadFromOffset(kLoadDoubleword, temp.AsRegister<GpuRegister>(), TR, entry_point_offset);
4315      // The entrypoint is null when the GC is not marking, this prevents one load compared to
4316      // checking GetIsGcMarking.
4317      __ Bnezc(temp.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
4318      __ Bind(slow_path->GetExitLabel());
4319    } else {
4320      // GC root loaded through a slow path for read barriers other
4321      // than Baker's.
4322      // /* GcRoot<mirror::Object>* */ root = obj + offset
4323      __ Daddiu64(root_reg, obj, static_cast<int32_t>(offset));
4324      // /* mirror::Object* */ root = root->Read()
4325      codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
4326    }
4327  } else {
4328    // Plain GC root load with no read barrier.
4329    // /* GcRoot<mirror::Object> */ root = *(obj + offset)
4330    __ LoadFromOffset(kLoadUnsignedWord, root_reg, obj, offset);
4331    // Note that GC roots are not affected by heap poisoning, thus we
4332    // do not have to unpoison `root_reg` here.
4333  }
4334}
4335
4336void CodeGeneratorMIPS64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
4337                                                                Location ref,
4338                                                                GpuRegister obj,
4339                                                                uint32_t offset,
4340                                                                Location temp,
4341                                                                bool needs_null_check) {
4342  DCHECK(kEmitCompilerReadBarrier);
4343  DCHECK(kUseBakerReadBarrier);
4344
4345  // /* HeapReference<Object> */ ref = *(obj + offset)
4346  Location no_index = Location::NoLocation();
4347  ScaleFactor no_scale_factor = TIMES_1;
4348  GenerateReferenceLoadWithBakerReadBarrier(instruction,
4349                                            ref,
4350                                            obj,
4351                                            offset,
4352                                            no_index,
4353                                            no_scale_factor,
4354                                            temp,
4355                                            needs_null_check);
4356}
4357
4358void CodeGeneratorMIPS64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
4359                                                                Location ref,
4360                                                                GpuRegister obj,
4361                                                                uint32_t data_offset,
4362                                                                Location index,
4363                                                                Location temp,
4364                                                                bool needs_null_check) {
4365  DCHECK(kEmitCompilerReadBarrier);
4366  DCHECK(kUseBakerReadBarrier);
4367
4368  static_assert(
4369      sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
4370      "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
4371  // /* HeapReference<Object> */ ref =
4372  //     *(obj + data_offset + index * sizeof(HeapReference<Object>))
4373  ScaleFactor scale_factor = TIMES_4;
4374  GenerateReferenceLoadWithBakerReadBarrier(instruction,
4375                                            ref,
4376                                            obj,
4377                                            data_offset,
4378                                            index,
4379                                            scale_factor,
4380                                            temp,
4381                                            needs_null_check);
4382}
4383
4384void CodeGeneratorMIPS64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
4385                                                                    Location ref,
4386                                                                    GpuRegister obj,
4387                                                                    uint32_t offset,
4388                                                                    Location index,
4389                                                                    ScaleFactor scale_factor,
4390                                                                    Location temp,
4391                                                                    bool needs_null_check,
4392                                                                    bool always_update_field) {
4393  DCHECK(kEmitCompilerReadBarrier);
4394  DCHECK(kUseBakerReadBarrier);
4395
4396  // In slow path based read barriers, the read barrier call is
4397  // inserted after the original load. However, in fast path based
4398  // Baker's read barriers, we need to perform the load of
4399  // mirror::Object::monitor_ *before* the original reference load.
4400  // This load-load ordering is required by the read barrier.
4401  // The fast path/slow path (for Baker's algorithm) should look like:
4402  //
4403  //   uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
4404  //   lfence;  // Load fence or artificial data dependency to prevent load-load reordering
4405  //   HeapReference<Object> ref = *src;  // Original reference load.
4406  //   bool is_gray = (rb_state == ReadBarrier::GrayState());
4407  //   if (is_gray) {
4408  //     ref = ReadBarrier::Mark(ref);  // Performed by runtime entrypoint slow path.
4409  //   }
4410  //
4411  // Note: the original implementation in ReadBarrier::Barrier is
4412  // slightly more complex as it performs additional checks that we do
4413  // not do here for performance reasons.
4414
4415  GpuRegister ref_reg = ref.AsRegister<GpuRegister>();
4416  GpuRegister temp_reg = temp.AsRegister<GpuRegister>();
4417  uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
4418
4419  // /* int32_t */ monitor = obj->monitor_
4420  __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
4421  if (needs_null_check) {
4422    MaybeRecordImplicitNullCheck(instruction);
4423  }
4424  // /* LockWord */ lock_word = LockWord(monitor)
4425  static_assert(sizeof(LockWord) == sizeof(int32_t),
4426                "art::LockWord and int32_t have different sizes.");
4427
4428  __ Sync(0);  // Barrier to prevent load-load reordering.
4429
4430  // The actual reference load.
4431  if (index.IsValid()) {
4432    // Load types involving an "index": ArrayGet,
4433    // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
4434    // intrinsics.
4435    // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
4436    if (index.IsConstant()) {
4437      size_t computed_offset =
4438          (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
4439      __ LoadFromOffset(kLoadUnsignedWord, ref_reg, obj, computed_offset);
4440    } else {
4441      GpuRegister index_reg = index.AsRegister<GpuRegister>();
4442      if (scale_factor == TIMES_1) {
4443        __ Daddu(TMP, index_reg, obj);
4444      } else {
4445        __ Dlsa(TMP, index_reg, obj, scale_factor);
4446      }
4447      __ LoadFromOffset(kLoadUnsignedWord, ref_reg, TMP, offset);
4448    }
4449  } else {
4450    // /* HeapReference<Object> */ ref = *(obj + offset)
4451    __ LoadFromOffset(kLoadUnsignedWord, ref_reg, obj, offset);
4452  }
4453
4454  // Object* ref = ref_addr->AsMirrorPtr()
4455  __ MaybeUnpoisonHeapReference(ref_reg);
4456
4457  // Slow path marking the object `ref` when it is gray.
4458  SlowPathCodeMIPS64* slow_path;
4459  if (always_update_field) {
4460    // ReadBarrierMarkAndUpdateFieldSlowPathMIPS64 only supports address
4461    // of the form `obj + field_offset`, where `obj` is a register and
4462    // `field_offset` is a register. Thus `offset` and `scale_factor`
4463    // above are expected to be null in this code path.
4464    DCHECK_EQ(offset, 0u);
4465    DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
4466    slow_path = new (GetGraph()->GetArena())
4467        ReadBarrierMarkAndUpdateFieldSlowPathMIPS64(instruction,
4468                                                    ref,
4469                                                    obj,
4470                                                    /* field_offset */ index,
4471                                                    temp_reg);
4472  } else {
4473    slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathMIPS64(instruction, ref);
4474  }
4475  AddSlowPath(slow_path);
4476
4477  // if (rb_state == ReadBarrier::GrayState())
4478  //   ref = ReadBarrier::Mark(ref);
4479  // Given the numeric representation, it's enough to check the low bit of the
4480  // rb_state. We do that by shifting the bit into the sign bit (31) and
4481  // performing a branch on less than zero.
4482  static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
4483  static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
4484  static_assert(LockWord::kReadBarrierStateSize == 1, "Expecting 1-bit read barrier state size");
4485  __ Sll(temp_reg, temp_reg, 31 - LockWord::kReadBarrierStateShift);
4486  __ Bltzc(temp_reg, slow_path->GetEntryLabel());
4487  __ Bind(slow_path->GetExitLabel());
4488}
4489
4490void CodeGeneratorMIPS64::GenerateReadBarrierSlow(HInstruction* instruction,
4491                                                  Location out,
4492                                                  Location ref,
4493                                                  Location obj,
4494                                                  uint32_t offset,
4495                                                  Location index) {
4496  DCHECK(kEmitCompilerReadBarrier);
4497
4498  // Insert a slow path based read barrier *after* the reference load.
4499  //
4500  // If heap poisoning is enabled, the unpoisoning of the loaded
4501  // reference will be carried out by the runtime within the slow
4502  // path.
4503  //
4504  // Note that `ref` currently does not get unpoisoned (when heap
4505  // poisoning is enabled), which is alright as the `ref` argument is
4506  // not used by the artReadBarrierSlow entry point.
4507  //
4508  // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
4509  SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena())
4510      ReadBarrierForHeapReferenceSlowPathMIPS64(instruction, out, ref, obj, offset, index);
4511  AddSlowPath(slow_path);
4512
4513  __ Bc(slow_path->GetEntryLabel());
4514  __ Bind(slow_path->GetExitLabel());
4515}
4516
4517void CodeGeneratorMIPS64::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
4518                                                       Location out,
4519                                                       Location ref,
4520                                                       Location obj,
4521                                                       uint32_t offset,
4522                                                       Location index) {
4523  if (kEmitCompilerReadBarrier) {
4524    // Baker's read barriers shall be handled by the fast path
4525    // (CodeGeneratorMIPS64::GenerateReferenceLoadWithBakerReadBarrier).
4526    DCHECK(!kUseBakerReadBarrier);
4527    // If heap poisoning is enabled, unpoisoning will be taken care of
4528    // by the runtime within the slow path.
4529    GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
4530  } else if (kPoisonHeapReferences) {
4531    __ UnpoisonHeapReference(out.AsRegister<GpuRegister>());
4532  }
4533}
4534
4535void CodeGeneratorMIPS64::GenerateReadBarrierForRootSlow(HInstruction* instruction,
4536                                                         Location out,
4537                                                         Location root) {
4538  DCHECK(kEmitCompilerReadBarrier);
4539
4540  // Insert a slow path based read barrier *after* the GC root load.
4541  //
4542  // Note that GC roots are not affected by heap poisoning, so we do
4543  // not need to do anything special for this here.
4544  SlowPathCodeMIPS64* slow_path =
4545      new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathMIPS64(instruction, out, root);
4546  AddSlowPath(slow_path);
4547
4548  __ Bc(slow_path->GetEntryLabel());
4549  __ Bind(slow_path->GetExitLabel());
4550}
4551
4552void LocationsBuilderMIPS64::VisitInstanceOf(HInstanceOf* instruction) {
4553  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4554  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
4555  switch (type_check_kind) {
4556    case TypeCheckKind::kExactCheck:
4557    case TypeCheckKind::kAbstractClassCheck:
4558    case TypeCheckKind::kClassHierarchyCheck:
4559    case TypeCheckKind::kArrayObjectCheck:
4560      call_kind =
4561          kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
4562      break;
4563    case TypeCheckKind::kArrayCheck:
4564    case TypeCheckKind::kUnresolvedCheck:
4565    case TypeCheckKind::kInterfaceCheck:
4566      call_kind = LocationSummary::kCallOnSlowPath;
4567      break;
4568  }
4569
4570  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4571  locations->SetInAt(0, Location::RequiresRegister());
4572  locations->SetInAt(1, Location::RequiresRegister());
4573  // The output does overlap inputs.
4574  // Note that TypeCheckSlowPathMIPS64 uses this register too.
4575  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4576  locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
4577}
4578
4579void InstructionCodeGeneratorMIPS64::VisitInstanceOf(HInstanceOf* instruction) {
4580  TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
4581  LocationSummary* locations = instruction->GetLocations();
4582  Location obj_loc = locations->InAt(0);
4583  GpuRegister obj = obj_loc.AsRegister<GpuRegister>();
4584  GpuRegister cls = locations->InAt(1).AsRegister<GpuRegister>();
4585  Location out_loc = locations->Out();
4586  GpuRegister out = out_loc.AsRegister<GpuRegister>();
4587  const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
4588  DCHECK_LE(num_temps, 1u);
4589  Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
4590  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4591  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4592  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4593  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
4594  Mips64Label done;
4595  SlowPathCodeMIPS64* slow_path = nullptr;
4596
4597  // Return 0 if `obj` is null.
4598  // Avoid this check if we know `obj` is not null.
4599  if (instruction->MustDoNullCheck()) {
4600    __ Move(out, ZERO);
4601    __ Beqzc(obj, &done);
4602  }
4603
4604  switch (type_check_kind) {
4605    case TypeCheckKind::kExactCheck: {
4606      // /* HeapReference<Class> */ out = obj->klass_
4607      GenerateReferenceLoadTwoRegisters(instruction,
4608                                        out_loc,
4609                                        obj_loc,
4610                                        class_offset,
4611                                        maybe_temp_loc,
4612                                        kCompilerReadBarrierOption);
4613      // Classes must be equal for the instanceof to succeed.
4614      __ Xor(out, out, cls);
4615      __ Sltiu(out, out, 1);
4616      break;
4617    }
4618
4619    case TypeCheckKind::kAbstractClassCheck: {
4620      // /* HeapReference<Class> */ out = obj->klass_
4621      GenerateReferenceLoadTwoRegisters(instruction,
4622                                        out_loc,
4623                                        obj_loc,
4624                                        class_offset,
4625                                        maybe_temp_loc,
4626                                        kCompilerReadBarrierOption);
4627      // If the class is abstract, we eagerly fetch the super class of the
4628      // object to avoid doing a comparison we know will fail.
4629      Mips64Label loop;
4630      __ Bind(&loop);
4631      // /* HeapReference<Class> */ out = out->super_class_
4632      GenerateReferenceLoadOneRegister(instruction,
4633                                       out_loc,
4634                                       super_offset,
4635                                       maybe_temp_loc,
4636                                       kCompilerReadBarrierOption);
4637      // If `out` is null, we use it for the result, and jump to `done`.
4638      __ Beqzc(out, &done);
4639      __ Bnec(out, cls, &loop);
4640      __ LoadConst32(out, 1);
4641      break;
4642    }
4643
4644    case TypeCheckKind::kClassHierarchyCheck: {
4645      // /* HeapReference<Class> */ out = obj->klass_
4646      GenerateReferenceLoadTwoRegisters(instruction,
4647                                        out_loc,
4648                                        obj_loc,
4649                                        class_offset,
4650                                        maybe_temp_loc,
4651                                        kCompilerReadBarrierOption);
4652      // Walk over the class hierarchy to find a match.
4653      Mips64Label loop, success;
4654      __ Bind(&loop);
4655      __ Beqc(out, cls, &success);
4656      // /* HeapReference<Class> */ out = out->super_class_
4657      GenerateReferenceLoadOneRegister(instruction,
4658                                       out_loc,
4659                                       super_offset,
4660                                       maybe_temp_loc,
4661                                       kCompilerReadBarrierOption);
4662      __ Bnezc(out, &loop);
4663      // If `out` is null, we use it for the result, and jump to `done`.
4664      __ Bc(&done);
4665      __ Bind(&success);
4666      __ LoadConst32(out, 1);
4667      break;
4668    }
4669
4670    case TypeCheckKind::kArrayObjectCheck: {
4671      // /* HeapReference<Class> */ out = obj->klass_
4672      GenerateReferenceLoadTwoRegisters(instruction,
4673                                        out_loc,
4674                                        obj_loc,
4675                                        class_offset,
4676                                        maybe_temp_loc,
4677                                        kCompilerReadBarrierOption);
4678      // Do an exact check.
4679      Mips64Label success;
4680      __ Beqc(out, cls, &success);
4681      // Otherwise, we need to check that the object's class is a non-primitive array.
4682      // /* HeapReference<Class> */ out = out->component_type_
4683      GenerateReferenceLoadOneRegister(instruction,
4684                                       out_loc,
4685                                       component_offset,
4686                                       maybe_temp_loc,
4687                                       kCompilerReadBarrierOption);
4688      // If `out` is null, we use it for the result, and jump to `done`.
4689      __ Beqzc(out, &done);
4690      __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
4691      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
4692      __ Sltiu(out, out, 1);
4693      __ Bc(&done);
4694      __ Bind(&success);
4695      __ LoadConst32(out, 1);
4696      break;
4697    }
4698
4699    case TypeCheckKind::kArrayCheck: {
4700      // No read barrier since the slow path will retry upon failure.
4701      // /* HeapReference<Class> */ out = obj->klass_
4702      GenerateReferenceLoadTwoRegisters(instruction,
4703                                        out_loc,
4704                                        obj_loc,
4705                                        class_offset,
4706                                        maybe_temp_loc,
4707                                        kWithoutReadBarrier);
4708      DCHECK(locations->OnlyCallsOnSlowPath());
4709      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS64(instruction,
4710                                                                       /* is_fatal */ false);
4711      codegen_->AddSlowPath(slow_path);
4712      __ Bnec(out, cls, slow_path->GetEntryLabel());
4713      __ LoadConst32(out, 1);
4714      break;
4715    }
4716
4717    case TypeCheckKind::kUnresolvedCheck:
4718    case TypeCheckKind::kInterfaceCheck: {
4719      // Note that we indeed only call on slow path, but we always go
4720      // into the slow path for the unresolved and interface check
4721      // cases.
4722      //
4723      // We cannot directly call the InstanceofNonTrivial runtime
4724      // entry point without resorting to a type checking slow path
4725      // here (i.e. by calling InvokeRuntime directly), as it would
4726      // require to assign fixed registers for the inputs of this
4727      // HInstanceOf instruction (following the runtime calling
4728      // convention), which might be cluttered by the potential first
4729      // read barrier emission at the beginning of this method.
4730      //
4731      // TODO: Introduce a new runtime entry point taking the object
4732      // to test (instead of its class) as argument, and let it deal
4733      // with the read barrier issues. This will let us refactor this
4734      // case of the `switch` code as it was previously (with a direct
4735      // call to the runtime not using a type checking slow path).
4736      // This should also be beneficial for the other cases above.
4737      DCHECK(locations->OnlyCallsOnSlowPath());
4738      slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS64(instruction,
4739                                                                       /* is_fatal */ false);
4740      codegen_->AddSlowPath(slow_path);
4741      __ Bc(slow_path->GetEntryLabel());
4742      break;
4743    }
4744  }
4745
4746  __ Bind(&done);
4747
4748  if (slow_path != nullptr) {
4749    __ Bind(slow_path->GetExitLabel());
4750  }
4751}
4752
4753void LocationsBuilderMIPS64::VisitIntConstant(HIntConstant* constant) {
4754  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
4755  locations->SetOut(Location::ConstantLocation(constant));
4756}
4757
4758void InstructionCodeGeneratorMIPS64::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
4759  // Will be generated at use site.
4760}
4761
4762void LocationsBuilderMIPS64::VisitNullConstant(HNullConstant* constant) {
4763  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
4764  locations->SetOut(Location::ConstantLocation(constant));
4765}
4766
4767void InstructionCodeGeneratorMIPS64::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
4768  // Will be generated at use site.
4769}
4770
4771void LocationsBuilderMIPS64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
4772  // The trampoline uses the same calling convention as dex calling conventions,
4773  // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
4774  // the method_idx.
4775  HandleInvoke(invoke);
4776}
4777
4778void InstructionCodeGeneratorMIPS64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
4779  codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
4780}
4781
4782void LocationsBuilderMIPS64::HandleInvoke(HInvoke* invoke) {
4783  InvokeDexCallingConventionVisitorMIPS64 calling_convention_visitor;
4784  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
4785}
4786
4787void LocationsBuilderMIPS64::VisitInvokeInterface(HInvokeInterface* invoke) {
4788  HandleInvoke(invoke);
4789  // The register T0 is required to be used for the hidden argument in
4790  // art_quick_imt_conflict_trampoline, so add the hidden argument.
4791  invoke->GetLocations()->AddTemp(Location::RegisterLocation(T0));
4792}
4793
4794void InstructionCodeGeneratorMIPS64::VisitInvokeInterface(HInvokeInterface* invoke) {
4795  // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
4796  GpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<GpuRegister>();
4797  Location receiver = invoke->GetLocations()->InAt(0);
4798  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4799  Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64PointerSize);
4800
4801  // Set the hidden argument.
4802  __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<GpuRegister>(),
4803                 invoke->GetDexMethodIndex());
4804
4805  // temp = object->GetClass();
4806  if (receiver.IsStackSlot()) {
4807    __ LoadFromOffset(kLoadUnsignedWord, temp, SP, receiver.GetStackIndex());
4808    __ LoadFromOffset(kLoadUnsignedWord, temp, temp, class_offset);
4809  } else {
4810    __ LoadFromOffset(kLoadUnsignedWord, temp, receiver.AsRegister<GpuRegister>(), class_offset);
4811  }
4812  codegen_->MaybeRecordImplicitNullCheck(invoke);
4813  // Instead of simply (possibly) unpoisoning `temp` here, we should
4814  // emit a read barrier for the previous class reference load.
4815  // However this is not required in practice, as this is an
4816  // intermediate/temporary reference and because the current
4817  // concurrent copying collector keeps the from-space memory
4818  // intact/accessible until the end of the marking phase (the
4819  // concurrent copying collector may not in the future).
4820  __ MaybeUnpoisonHeapReference(temp);
4821  __ LoadFromOffset(kLoadDoubleword, temp, temp,
4822      mirror::Class::ImtPtrOffset(kMips64PointerSize).Uint32Value());
4823  uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
4824      invoke->GetImtIndex(), kMips64PointerSize));
4825  // temp = temp->GetImtEntryAt(method_offset);
4826  __ LoadFromOffset(kLoadDoubleword, temp, temp, method_offset);
4827  // T9 = temp->GetEntryPoint();
4828  __ LoadFromOffset(kLoadDoubleword, T9, temp, entry_point.Int32Value());
4829  // T9();
4830  __ Jalr(T9);
4831  __ Nop();
4832  DCHECK(!codegen_->IsLeafMethod());
4833  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
4834}
4835
4836void LocationsBuilderMIPS64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
4837  IntrinsicLocationsBuilderMIPS64 intrinsic(codegen_);
4838  if (intrinsic.TryDispatch(invoke)) {
4839    return;
4840  }
4841
4842  HandleInvoke(invoke);
4843}
4844
4845void LocationsBuilderMIPS64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
4846  // Explicit clinit checks triggered by static invokes must have been pruned by
4847  // art::PrepareForRegisterAllocation.
4848  DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
4849
4850  IntrinsicLocationsBuilderMIPS64 intrinsic(codegen_);
4851  if (intrinsic.TryDispatch(invoke)) {
4852    return;
4853  }
4854
4855  HandleInvoke(invoke);
4856}
4857
4858void LocationsBuilderMIPS64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
4859  HandleInvoke(invoke);
4860}
4861
4862void InstructionCodeGeneratorMIPS64::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
4863  codegen_->GenerateInvokePolymorphicCall(invoke);
4864}
4865
4866static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS64* codegen) {
4867  if (invoke->GetLocations()->Intrinsified()) {
4868    IntrinsicCodeGeneratorMIPS64 intrinsic(codegen);
4869    intrinsic.Dispatch(invoke);
4870    return true;
4871  }
4872  return false;
4873}
4874
4875HLoadString::LoadKind CodeGeneratorMIPS64::GetSupportedLoadStringKind(
4876    HLoadString::LoadKind desired_string_load_kind) {
4877  bool fallback_load = false;
4878  switch (desired_string_load_kind) {
4879    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
4880      DCHECK(!GetCompilerOptions().GetCompilePic());
4881      break;
4882    case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
4883      DCHECK(GetCompilerOptions().GetCompilePic());
4884      break;
4885    case HLoadString::LoadKind::kBootImageAddress:
4886      break;
4887    case HLoadString::LoadKind::kBssEntry:
4888      DCHECK(!Runtime::Current()->UseJitCompilation());
4889      break;
4890    case HLoadString::LoadKind::kDexCacheViaMethod:
4891      break;
4892    case HLoadString::LoadKind::kJitTableAddress:
4893      DCHECK(Runtime::Current()->UseJitCompilation());
4894      break;
4895  }
4896  if (fallback_load) {
4897    desired_string_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
4898  }
4899  return desired_string_load_kind;
4900}
4901
4902HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind(
4903    HLoadClass::LoadKind desired_class_load_kind) {
4904  bool fallback_load = false;
4905  switch (desired_class_load_kind) {
4906    case HLoadClass::LoadKind::kInvalid:
4907      LOG(FATAL) << "UNREACHABLE";
4908      UNREACHABLE();
4909    case HLoadClass::LoadKind::kReferrersClass:
4910      break;
4911    case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
4912      DCHECK(!GetCompilerOptions().GetCompilePic());
4913      break;
4914    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
4915      DCHECK(GetCompilerOptions().GetCompilePic());
4916      break;
4917    case HLoadClass::LoadKind::kBootImageAddress:
4918      break;
4919    case HLoadClass::LoadKind::kBssEntry:
4920      DCHECK(!Runtime::Current()->UseJitCompilation());
4921      break;
4922    case HLoadClass::LoadKind::kJitTableAddress:
4923      DCHECK(Runtime::Current()->UseJitCompilation());
4924      break;
4925    case HLoadClass::LoadKind::kDexCacheViaMethod:
4926      break;
4927  }
4928  if (fallback_load) {
4929    desired_class_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
4930  }
4931  return desired_class_load_kind;
4932}
4933
4934HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch(
4935      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
4936      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
4937  // On MIPS64 we support all dispatch types.
4938  return desired_dispatch_info;
4939}
4940
4941void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
4942  // All registers are assumed to be correctly set up per the calling convention.
4943  Location callee_method = temp;  // For all kinds except kRecursive, callee will be in temp.
4944  HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
4945  HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
4946
4947  switch (method_load_kind) {
4948    case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
4949      // temp = thread->string_init_entrypoint
4950      uint32_t offset =
4951          GetThreadOffset<kMips64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
4952      __ LoadFromOffset(kLoadDoubleword,
4953                        temp.AsRegister<GpuRegister>(),
4954                        TR,
4955                        offset);
4956      break;
4957    }
4958    case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
4959      callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
4960      break;
4961    case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
4962      __ LoadLiteral(temp.AsRegister<GpuRegister>(),
4963                     kLoadDoubleword,
4964                     DeduplicateUint64Literal(invoke->GetMethodAddress()));
4965      break;
4966    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
4967      uint32_t offset = invoke->GetDexCacheArrayOffset();
4968      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
4969          NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset);
4970      EmitPcRelativeAddressPlaceholderHigh(info, AT);
4971      __ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
4972      break;
4973    }
4974    case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
4975      Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
4976      GpuRegister reg = temp.AsRegister<GpuRegister>();
4977      GpuRegister method_reg;
4978      if (current_method.IsRegister()) {
4979        method_reg = current_method.AsRegister<GpuRegister>();
4980      } else {
4981        // TODO: use the appropriate DCHECK() here if possible.
4982        // DCHECK(invoke->GetLocations()->Intrinsified());
4983        DCHECK(!current_method.IsValid());
4984        method_reg = reg;
4985        __ Ld(reg, SP, kCurrentMethodStackOffset);
4986      }
4987
4988      // temp = temp->dex_cache_resolved_methods_;
4989      __ LoadFromOffset(kLoadDoubleword,
4990                        reg,
4991                        method_reg,
4992                        ArtMethod::DexCacheResolvedMethodsOffset(kMips64PointerSize).Int32Value());
4993      // temp = temp[index_in_cache];
4994      // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
4995      uint32_t index_in_cache = invoke->GetDexMethodIndex();
4996      __ LoadFromOffset(kLoadDoubleword,
4997                        reg,
4998                        reg,
4999                        CodeGenerator::GetCachePointerOffset(index_in_cache));
5000      break;
5001    }
5002  }
5003
5004  switch (code_ptr_location) {
5005    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
5006      __ Balc(&frame_entry_label_);
5007      break;
5008    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
5009      // T9 = callee_method->entry_point_from_quick_compiled_code_;
5010      __ LoadFromOffset(kLoadDoubleword,
5011                        T9,
5012                        callee_method.AsRegister<GpuRegister>(),
5013                        ArtMethod::EntryPointFromQuickCompiledCodeOffset(
5014                            kMips64PointerSize).Int32Value());
5015      // T9()
5016      __ Jalr(T9);
5017      __ Nop();
5018      break;
5019  }
5020  DCHECK(!IsLeafMethod());
5021}
5022
5023void InstructionCodeGeneratorMIPS64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
5024  // Explicit clinit checks triggered by static invokes must have been pruned by
5025  // art::PrepareForRegisterAllocation.
5026  DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
5027
5028  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
5029    return;
5030  }
5031
5032  LocationSummary* locations = invoke->GetLocations();
5033  codegen_->GenerateStaticOrDirectCall(invoke,
5034                                       locations->HasTemps()
5035                                           ? locations->GetTemp(0)
5036                                           : Location::NoLocation());
5037  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
5038}
5039
5040void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
5041  // Use the calling convention instead of the location of the receiver, as
5042  // intrinsics may have put the receiver in a different register. In the intrinsics
5043  // slow path, the arguments have been moved to the right place, so here we are
5044  // guaranteed that the receiver is the first register of the calling convention.
5045  InvokeDexCallingConvention calling_convention;
5046  GpuRegister receiver = calling_convention.GetRegisterAt(0);
5047
5048  GpuRegister temp = temp_location.AsRegister<GpuRegister>();
5049  size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5050      invoke->GetVTableIndex(), kMips64PointerSize).SizeValue();
5051  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5052  Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64PointerSize);
5053
5054  // temp = object->GetClass();
5055  __ LoadFromOffset(kLoadUnsignedWord, temp, receiver, class_offset);
5056  MaybeRecordImplicitNullCheck(invoke);
5057  // Instead of simply (possibly) unpoisoning `temp` here, we should
5058  // emit a read barrier for the previous class reference load.
5059  // However this is not required in practice, as this is an
5060  // intermediate/temporary reference and because the current
5061  // concurrent copying collector keeps the from-space memory
5062  // intact/accessible until the end of the marking phase (the
5063  // concurrent copying collector may not in the future).
5064  __ MaybeUnpoisonHeapReference(temp);
5065  // temp = temp->GetMethodAt(method_offset);
5066  __ LoadFromOffset(kLoadDoubleword, temp, temp, method_offset);
5067  // T9 = temp->GetEntryPoint();
5068  __ LoadFromOffset(kLoadDoubleword, T9, temp, entry_point.Int32Value());
5069  // T9();
5070  __ Jalr(T9);
5071  __ Nop();
5072}
5073
5074void InstructionCodeGeneratorMIPS64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
5075  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
5076    return;
5077  }
5078
5079  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
5080  DCHECK(!codegen_->IsLeafMethod());
5081  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
5082}
5083
5084void LocationsBuilderMIPS64::VisitLoadClass(HLoadClass* cls) {
5085  HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5086  if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
5087    InvokeRuntimeCallingConvention calling_convention;
5088    CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
5089        cls,
5090        Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5091        calling_convention.GetReturnLocation(Primitive::kPrimNot));
5092    return;
5093  }
5094  DCHECK(!cls->NeedsAccessCheck());
5095
5096  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
5097  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
5098      ? LocationSummary::kCallOnSlowPath
5099      : LocationSummary::kNoCall;
5100  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
5101  if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
5102    locations->SetInAt(0, Location::RequiresRegister());
5103  }
5104  locations->SetOut(Location::RequiresRegister());
5105}
5106
5107// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5108// move.
5109void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
5110  HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5111  if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
5112    codegen_->GenerateLoadClassRuntimeCall(cls);
5113    return;
5114  }
5115  DCHECK(!cls->NeedsAccessCheck());
5116
5117  LocationSummary* locations = cls->GetLocations();
5118  Location out_loc = locations->Out();
5119  GpuRegister out = out_loc.AsRegister<GpuRegister>();
5120  GpuRegister current_method_reg = ZERO;
5121  if (load_kind == HLoadClass::LoadKind::kReferrersClass ||
5122      load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
5123      current_method_reg = locations->InAt(0).AsRegister<GpuRegister>();
5124  }
5125
5126  const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
5127      ? kWithoutReadBarrier
5128      : kCompilerReadBarrierOption;
5129  bool generate_null_check = false;
5130  switch (load_kind) {
5131    case HLoadClass::LoadKind::kReferrersClass:
5132      DCHECK(!cls->CanCallRuntime());
5133      DCHECK(!cls->MustGenerateClinitCheck());
5134      // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5135      GenerateGcRootFieldLoad(cls,
5136                              out_loc,
5137                              current_method_reg,
5138                              ArtMethod::DeclaringClassOffset().Int32Value(),
5139                              read_barrier_option);
5140      break;
5141    case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5142      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
5143      DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
5144      __ LoadLiteral(out,
5145                     kLoadUnsignedWord,
5146                     codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5147                                                               cls->GetTypeIndex()));
5148      break;
5149    case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
5150      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
5151      DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
5152      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
5153          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
5154      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, AT);
5155      __ Daddiu(out, AT, /* placeholder */ 0x5678);
5156      break;
5157    }
5158    case HLoadClass::LoadKind::kBootImageAddress: {
5159      DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
5160      uint32_t address = dchecked_integral_cast<uint32_t>(
5161          reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
5162      DCHECK_NE(address, 0u);
5163      __ LoadLiteral(out,
5164                     kLoadUnsignedWord,
5165                     codegen_->DeduplicateBootImageAddressLiteral(address));
5166      break;
5167    }
5168    case HLoadClass::LoadKind::kBssEntry: {
5169      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
5170          codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
5171      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out);
5172      GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678, read_barrier_option);
5173      generate_null_check = true;
5174      break;
5175    }
5176    case HLoadClass::LoadKind::kJitTableAddress:
5177      __ LoadLiteral(out,
5178                     kLoadUnsignedWord,
5179                     codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
5180                                                          cls->GetTypeIndex(),
5181                                                          cls->GetClass()));
5182      GenerateGcRootFieldLoad(cls, out_loc, out, 0, read_barrier_option);
5183      break;
5184    case HLoadClass::LoadKind::kDexCacheViaMethod:
5185    case HLoadClass::LoadKind::kInvalid:
5186      LOG(FATAL) << "UNREACHABLE";
5187      UNREACHABLE();
5188  }
5189
5190  if (generate_null_check || cls->MustGenerateClinitCheck()) {
5191    DCHECK(cls->CanCallRuntime());
5192    SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS64(
5193        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5194    codegen_->AddSlowPath(slow_path);
5195    if (generate_null_check) {
5196      __ Beqzc(out, slow_path->GetEntryLabel());
5197    }
5198    if (cls->MustGenerateClinitCheck()) {
5199      GenerateClassInitializationCheck(slow_path, out);
5200    } else {
5201      __ Bind(slow_path->GetExitLabel());
5202    }
5203  }
5204}
5205
5206static int32_t GetExceptionTlsOffset() {
5207  return Thread::ExceptionOffset<kMips64PointerSize>().Int32Value();
5208}
5209
5210void LocationsBuilderMIPS64::VisitLoadException(HLoadException* load) {
5211  LocationSummary* locations =
5212      new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5213  locations->SetOut(Location::RequiresRegister());
5214}
5215
5216void InstructionCodeGeneratorMIPS64::VisitLoadException(HLoadException* load) {
5217  GpuRegister out = load->GetLocations()->Out().AsRegister<GpuRegister>();
5218  __ LoadFromOffset(kLoadUnsignedWord, out, TR, GetExceptionTlsOffset());
5219}
5220
5221void LocationsBuilderMIPS64::VisitClearException(HClearException* clear) {
5222  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5223}
5224
5225void InstructionCodeGeneratorMIPS64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5226  __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
5227}
5228
5229void LocationsBuilderMIPS64::VisitLoadString(HLoadString* load) {
5230  HLoadString::LoadKind load_kind = load->GetLoadKind();
5231  LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
5232  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
5233  if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
5234    InvokeRuntimeCallingConvention calling_convention;
5235    locations->SetOut(calling_convention.GetReturnLocation(load->GetType()));
5236  } else {
5237    locations->SetOut(Location::RequiresRegister());
5238  }
5239}
5240
5241// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5242// move.
5243void InstructionCodeGeneratorMIPS64::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
5244  HLoadString::LoadKind load_kind = load->GetLoadKind();
5245  LocationSummary* locations = load->GetLocations();
5246  Location out_loc = locations->Out();
5247  GpuRegister out = out_loc.AsRegister<GpuRegister>();
5248
5249  switch (load_kind) {
5250    case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5251      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
5252      __ LoadLiteral(out,
5253                     kLoadUnsignedWord,
5254                     codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5255                                                                 load->GetStringIndex()));
5256      return;  // No dex cache slow path.
5257    case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
5258      DCHECK(codegen_->GetCompilerOptions().IsBootImage());
5259      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
5260          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5261      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, AT);
5262      __ Daddiu(out, AT, /* placeholder */ 0x5678);
5263      return;  // No dex cache slow path.
5264    }
5265    case HLoadString::LoadKind::kBootImageAddress: {
5266      uint32_t address = dchecked_integral_cast<uint32_t>(
5267          reinterpret_cast<uintptr_t>(load->GetString().Get()));
5268      DCHECK_NE(address, 0u);
5269      __ LoadLiteral(out,
5270                     kLoadUnsignedWord,
5271                     codegen_->DeduplicateBootImageAddressLiteral(address));
5272      return;  // No dex cache slow path.
5273    }
5274    case HLoadString::LoadKind::kBssEntry: {
5275      DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
5276      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
5277          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
5278      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out);
5279      GenerateGcRootFieldLoad(load,
5280                              out_loc,
5281                              out,
5282                              /* placeholder */ 0x5678,
5283                              kCompilerReadBarrierOption);
5284      SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load);
5285      codegen_->AddSlowPath(slow_path);
5286      __ Beqzc(out, slow_path->GetEntryLabel());
5287      __ Bind(slow_path->GetExitLabel());
5288      return;
5289    }
5290    case HLoadString::LoadKind::kJitTableAddress:
5291      __ LoadLiteral(out,
5292                     kLoadUnsignedWord,
5293                     codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
5294                                                           load->GetStringIndex(),
5295                                                           load->GetString()));
5296      GenerateGcRootFieldLoad(load, out_loc, out, 0, kCompilerReadBarrierOption);
5297      return;
5298    default:
5299      break;
5300  }
5301
5302  // TODO: Re-add the compiler code to do string dex cache lookup again.
5303  DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
5304  InvokeRuntimeCallingConvention calling_convention;
5305  __ LoadConst32(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
5306  codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
5307  CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
5308}
5309
5310void LocationsBuilderMIPS64::VisitLongConstant(HLongConstant* constant) {
5311  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
5312  locations->SetOut(Location::ConstantLocation(constant));
5313}
5314
5315void InstructionCodeGeneratorMIPS64::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
5316  // Will be generated at use site.
5317}
5318
5319void LocationsBuilderMIPS64::VisitMonitorOperation(HMonitorOperation* instruction) {
5320  LocationSummary* locations =
5321      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
5322  InvokeRuntimeCallingConvention calling_convention;
5323  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5324}
5325
5326void InstructionCodeGeneratorMIPS64::VisitMonitorOperation(HMonitorOperation* instruction) {
5327  codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
5328                          instruction,
5329                          instruction->GetDexPc());
5330  if (instruction->IsEnter()) {
5331    CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5332  } else {
5333    CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5334  }
5335}
5336
5337void LocationsBuilderMIPS64::VisitMul(HMul* mul) {
5338  LocationSummary* locations =
5339      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
5340  switch (mul->GetResultType()) {
5341    case Primitive::kPrimInt:
5342    case Primitive::kPrimLong:
5343      locations->SetInAt(0, Location::RequiresRegister());
5344      locations->SetInAt(1, Location::RequiresRegister());
5345      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5346      break;
5347
5348    case Primitive::kPrimFloat:
5349    case Primitive::kPrimDouble:
5350      locations->SetInAt(0, Location::RequiresFpuRegister());
5351      locations->SetInAt(1, Location::RequiresFpuRegister());
5352      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5353      break;
5354
5355    default:
5356      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
5357  }
5358}
5359
5360void InstructionCodeGeneratorMIPS64::VisitMul(HMul* instruction) {
5361  Primitive::Type type = instruction->GetType();
5362  LocationSummary* locations = instruction->GetLocations();
5363
5364  switch (type) {
5365    case Primitive::kPrimInt:
5366    case Primitive::kPrimLong: {
5367      GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
5368      GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
5369      GpuRegister rhs = locations->InAt(1).AsRegister<GpuRegister>();
5370      if (type == Primitive::kPrimInt)
5371        __ MulR6(dst, lhs, rhs);
5372      else
5373        __ Dmul(dst, lhs, rhs);
5374      break;
5375    }
5376    case Primitive::kPrimFloat:
5377    case Primitive::kPrimDouble: {
5378      FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
5379      FpuRegister lhs = locations->InAt(0).AsFpuRegister<FpuRegister>();
5380      FpuRegister rhs = locations->InAt(1).AsFpuRegister<FpuRegister>();
5381      if (type == Primitive::kPrimFloat)
5382        __ MulS(dst, lhs, rhs);
5383      else
5384        __ MulD(dst, lhs, rhs);
5385      break;
5386    }
5387    default:
5388      LOG(FATAL) << "Unexpected mul type " << type;
5389  }
5390}
5391
5392void LocationsBuilderMIPS64::VisitNeg(HNeg* neg) {
5393  LocationSummary* locations =
5394      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
5395  switch (neg->GetResultType()) {
5396    case Primitive::kPrimInt:
5397    case Primitive::kPrimLong:
5398      locations->SetInAt(0, Location::RequiresRegister());
5399      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5400      break;
5401
5402    case Primitive::kPrimFloat:
5403    case Primitive::kPrimDouble:
5404      locations->SetInAt(0, Location::RequiresFpuRegister());
5405      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5406      break;
5407
5408    default:
5409      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
5410  }
5411}
5412
5413void InstructionCodeGeneratorMIPS64::VisitNeg(HNeg* instruction) {
5414  Primitive::Type type = instruction->GetType();
5415  LocationSummary* locations = instruction->GetLocations();
5416
5417  switch (type) {
5418    case Primitive::kPrimInt:
5419    case Primitive::kPrimLong: {
5420      GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
5421      GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
5422      if (type == Primitive::kPrimInt)
5423        __ Subu(dst, ZERO, src);
5424      else
5425        __ Dsubu(dst, ZERO, src);
5426      break;
5427    }
5428    case Primitive::kPrimFloat:
5429    case Primitive::kPrimDouble: {
5430      FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
5431      FpuRegister src = locations->InAt(0).AsFpuRegister<FpuRegister>();
5432      if (type == Primitive::kPrimFloat)
5433        __ NegS(dst, src);
5434      else
5435        __ NegD(dst, src);
5436      break;
5437    }
5438    default:
5439      LOG(FATAL) << "Unexpected neg type " << type;
5440  }
5441}
5442
5443void LocationsBuilderMIPS64::VisitNewArray(HNewArray* instruction) {
5444  LocationSummary* locations =
5445      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
5446  InvokeRuntimeCallingConvention calling_convention;
5447  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
5448  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5449  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5450}
5451
5452void InstructionCodeGeneratorMIPS64::VisitNewArray(HNewArray* instruction) {
5453  // Note: if heap poisoning is enabled, the entry point takes care
5454  // of poisoning the reference.
5455  codegen_->InvokeRuntime(kQuickAllocArrayResolved, instruction, instruction->GetDexPc());
5456  CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
5457}
5458
5459void LocationsBuilderMIPS64::VisitNewInstance(HNewInstance* instruction) {
5460  LocationSummary* locations =
5461      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
5462  InvokeRuntimeCallingConvention calling_convention;
5463  if (instruction->IsStringAlloc()) {
5464    locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
5465  } else {
5466    locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5467  }
5468  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
5469}
5470
5471void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction) {
5472  // Note: if heap poisoning is enabled, the entry point takes care
5473  // of poisoning the reference.
5474  if (instruction->IsStringAlloc()) {
5475    // String is allocated through StringFactory. Call NewEmptyString entry point.
5476    GpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister<GpuRegister>();
5477    MemberOffset code_offset =
5478        ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64PointerSize);
5479    __ LoadFromOffset(kLoadDoubleword, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
5480    __ LoadFromOffset(kLoadDoubleword, T9, temp, code_offset.Int32Value());
5481    __ Jalr(T9);
5482    __ Nop();
5483    codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
5484  } else {
5485    codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
5486    CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
5487  }
5488}
5489
5490void LocationsBuilderMIPS64::VisitNot(HNot* instruction) {
5491  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
5492  locations->SetInAt(0, Location::RequiresRegister());
5493  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5494}
5495
5496void InstructionCodeGeneratorMIPS64::VisitNot(HNot* instruction) {
5497  Primitive::Type type = instruction->GetType();
5498  LocationSummary* locations = instruction->GetLocations();
5499
5500  switch (type) {
5501    case Primitive::kPrimInt:
5502    case Primitive::kPrimLong: {
5503      GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
5504      GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
5505      __ Nor(dst, src, ZERO);
5506      break;
5507    }
5508
5509    default:
5510      LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
5511  }
5512}
5513
5514void LocationsBuilderMIPS64::VisitBooleanNot(HBooleanNot* instruction) {
5515  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
5516  locations->SetInAt(0, Location::RequiresRegister());
5517  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5518}
5519
5520void InstructionCodeGeneratorMIPS64::VisitBooleanNot(HBooleanNot* instruction) {
5521  LocationSummary* locations = instruction->GetLocations();
5522  __ Xori(locations->Out().AsRegister<GpuRegister>(),
5523          locations->InAt(0).AsRegister<GpuRegister>(),
5524          1);
5525}
5526
5527void LocationsBuilderMIPS64::VisitNullCheck(HNullCheck* instruction) {
5528  LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
5529  locations->SetInAt(0, Location::RequiresRegister());
5530}
5531
5532void CodeGeneratorMIPS64::GenerateImplicitNullCheck(HNullCheck* instruction) {
5533  if (CanMoveNullCheckToUser(instruction)) {
5534    return;
5535  }
5536  Location obj = instruction->GetLocations()->InAt(0);
5537
5538  __ Lw(ZERO, obj.AsRegister<GpuRegister>(), 0);
5539  RecordPcInfo(instruction, instruction->GetDexPc());
5540}
5541
5542void CodeGeneratorMIPS64::GenerateExplicitNullCheck(HNullCheck* instruction) {
5543  SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathMIPS64(instruction);
5544  AddSlowPath(slow_path);
5545
5546  Location obj = instruction->GetLocations()->InAt(0);
5547
5548  __ Beqzc(obj.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
5549}
5550
5551void InstructionCodeGeneratorMIPS64::VisitNullCheck(HNullCheck* instruction) {
5552  codegen_->GenerateNullCheck(instruction);
5553}
5554
5555void LocationsBuilderMIPS64::VisitOr(HOr* instruction) {
5556  HandleBinaryOp(instruction);
5557}
5558
5559void InstructionCodeGeneratorMIPS64::VisitOr(HOr* instruction) {
5560  HandleBinaryOp(instruction);
5561}
5562
5563void LocationsBuilderMIPS64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
5564  LOG(FATAL) << "Unreachable";
5565}
5566
5567void InstructionCodeGeneratorMIPS64::VisitParallelMove(HParallelMove* instruction) {
5568  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5569}
5570
5571void LocationsBuilderMIPS64::VisitParameterValue(HParameterValue* instruction) {
5572  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
5573  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
5574  if (location.IsStackSlot()) {
5575    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5576  } else if (location.IsDoubleStackSlot()) {
5577    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5578  }
5579  locations->SetOut(location);
5580}
5581
5582void InstructionCodeGeneratorMIPS64::VisitParameterValue(HParameterValue* instruction
5583                                                         ATTRIBUTE_UNUSED) {
5584  // Nothing to do, the parameter is already at its location.
5585}
5586
5587void LocationsBuilderMIPS64::VisitCurrentMethod(HCurrentMethod* instruction) {
5588  LocationSummary* locations =
5589      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5590  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
5591}
5592
5593void InstructionCodeGeneratorMIPS64::VisitCurrentMethod(HCurrentMethod* instruction
5594                                                        ATTRIBUTE_UNUSED) {
5595  // Nothing to do, the method is already at its location.
5596}
5597
5598void LocationsBuilderMIPS64::VisitPhi(HPhi* instruction) {
5599  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
5600  for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
5601    locations->SetInAt(i, Location::Any());
5602  }
5603  locations->SetOut(Location::Any());
5604}
5605
5606void InstructionCodeGeneratorMIPS64::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
5607  LOG(FATAL) << "Unreachable";
5608}
5609
5610void LocationsBuilderMIPS64::VisitRem(HRem* rem) {
5611  Primitive::Type type = rem->GetResultType();
5612  LocationSummary::CallKind call_kind =
5613      Primitive::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
5614                                           : LocationSummary::kNoCall;
5615  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
5616
5617  switch (type) {
5618    case Primitive::kPrimInt:
5619    case Primitive::kPrimLong:
5620      locations->SetInAt(0, Location::RequiresRegister());
5621      locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
5622      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5623      break;
5624
5625    case Primitive::kPrimFloat:
5626    case Primitive::kPrimDouble: {
5627      InvokeRuntimeCallingConvention calling_convention;
5628      locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
5629      locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
5630      locations->SetOut(calling_convention.GetReturnLocation(type));
5631      break;
5632    }
5633
5634    default:
5635      LOG(FATAL) << "Unexpected rem type " << type;
5636  }
5637}
5638
5639void InstructionCodeGeneratorMIPS64::VisitRem(HRem* instruction) {
5640  Primitive::Type type = instruction->GetType();
5641
5642  switch (type) {
5643    case Primitive::kPrimInt:
5644    case Primitive::kPrimLong:
5645      GenerateDivRemIntegral(instruction);
5646      break;
5647
5648    case Primitive::kPrimFloat:
5649    case Primitive::kPrimDouble: {
5650      QuickEntrypointEnum entrypoint = (type == Primitive::kPrimFloat) ? kQuickFmodf : kQuickFmod;
5651      codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
5652      if (type == Primitive::kPrimFloat) {
5653        CheckEntrypointTypes<kQuickFmodf, float, float, float>();
5654      } else {
5655        CheckEntrypointTypes<kQuickFmod, double, double, double>();
5656      }
5657      break;
5658    }
5659    default:
5660      LOG(FATAL) << "Unexpected rem type " << type;
5661  }
5662}
5663
5664void LocationsBuilderMIPS64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
5665  memory_barrier->SetLocations(nullptr);
5666}
5667
5668void InstructionCodeGeneratorMIPS64::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
5669  GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
5670}
5671
5672void LocationsBuilderMIPS64::VisitReturn(HReturn* ret) {
5673  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
5674  Primitive::Type return_type = ret->InputAt(0)->GetType();
5675  locations->SetInAt(0, Mips64ReturnLocation(return_type));
5676}
5677
5678void InstructionCodeGeneratorMIPS64::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
5679  codegen_->GenerateFrameExit();
5680}
5681
5682void LocationsBuilderMIPS64::VisitReturnVoid(HReturnVoid* ret) {
5683  ret->SetLocations(nullptr);
5684}
5685
5686void InstructionCodeGeneratorMIPS64::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
5687  codegen_->GenerateFrameExit();
5688}
5689
5690void LocationsBuilderMIPS64::VisitRor(HRor* ror) {
5691  HandleShift(ror);
5692}
5693
5694void InstructionCodeGeneratorMIPS64::VisitRor(HRor* ror) {
5695  HandleShift(ror);
5696}
5697
5698void LocationsBuilderMIPS64::VisitShl(HShl* shl) {
5699  HandleShift(shl);
5700}
5701
5702void InstructionCodeGeneratorMIPS64::VisitShl(HShl* shl) {
5703  HandleShift(shl);
5704}
5705
5706void LocationsBuilderMIPS64::VisitShr(HShr* shr) {
5707  HandleShift(shr);
5708}
5709
5710void InstructionCodeGeneratorMIPS64::VisitShr(HShr* shr) {
5711  HandleShift(shr);
5712}
5713
5714void LocationsBuilderMIPS64::VisitSub(HSub* instruction) {
5715  HandleBinaryOp(instruction);
5716}
5717
5718void InstructionCodeGeneratorMIPS64::VisitSub(HSub* instruction) {
5719  HandleBinaryOp(instruction);
5720}
5721
5722void LocationsBuilderMIPS64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5723  HandleFieldGet(instruction, instruction->GetFieldInfo());
5724}
5725
5726void InstructionCodeGeneratorMIPS64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5727  HandleFieldGet(instruction, instruction->GetFieldInfo());
5728}
5729
5730void LocationsBuilderMIPS64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5731  HandleFieldSet(instruction, instruction->GetFieldInfo());
5732}
5733
5734void InstructionCodeGeneratorMIPS64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5735  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
5736}
5737
5738void LocationsBuilderMIPS64::VisitUnresolvedInstanceFieldGet(
5739    HUnresolvedInstanceFieldGet* instruction) {
5740  FieldAccessCallingConventionMIPS64 calling_convention;
5741  codegen_->CreateUnresolvedFieldLocationSummary(
5742      instruction, instruction->GetFieldType(), calling_convention);
5743}
5744
5745void InstructionCodeGeneratorMIPS64::VisitUnresolvedInstanceFieldGet(
5746    HUnresolvedInstanceFieldGet* instruction) {
5747  FieldAccessCallingConventionMIPS64 calling_convention;
5748  codegen_->GenerateUnresolvedFieldAccess(instruction,
5749                                          instruction->GetFieldType(),
5750                                          instruction->GetFieldIndex(),
5751                                          instruction->GetDexPc(),
5752                                          calling_convention);
5753}
5754
5755void LocationsBuilderMIPS64::VisitUnresolvedInstanceFieldSet(
5756    HUnresolvedInstanceFieldSet* instruction) {
5757  FieldAccessCallingConventionMIPS64 calling_convention;
5758  codegen_->CreateUnresolvedFieldLocationSummary(
5759      instruction, instruction->GetFieldType(), calling_convention);
5760}
5761
5762void InstructionCodeGeneratorMIPS64::VisitUnresolvedInstanceFieldSet(
5763    HUnresolvedInstanceFieldSet* instruction) {
5764  FieldAccessCallingConventionMIPS64 calling_convention;
5765  codegen_->GenerateUnresolvedFieldAccess(instruction,
5766                                          instruction->GetFieldType(),
5767                                          instruction->GetFieldIndex(),
5768                                          instruction->GetDexPc(),
5769                                          calling_convention);
5770}
5771
5772void LocationsBuilderMIPS64::VisitUnresolvedStaticFieldGet(
5773    HUnresolvedStaticFieldGet* instruction) {
5774  FieldAccessCallingConventionMIPS64 calling_convention;
5775  codegen_->CreateUnresolvedFieldLocationSummary(
5776      instruction, instruction->GetFieldType(), calling_convention);
5777}
5778
5779void InstructionCodeGeneratorMIPS64::VisitUnresolvedStaticFieldGet(
5780    HUnresolvedStaticFieldGet* instruction) {
5781  FieldAccessCallingConventionMIPS64 calling_convention;
5782  codegen_->GenerateUnresolvedFieldAccess(instruction,
5783                                          instruction->GetFieldType(),
5784                                          instruction->GetFieldIndex(),
5785                                          instruction->GetDexPc(),
5786                                          calling_convention);
5787}
5788
5789void LocationsBuilderMIPS64::VisitUnresolvedStaticFieldSet(
5790    HUnresolvedStaticFieldSet* instruction) {
5791  FieldAccessCallingConventionMIPS64 calling_convention;
5792  codegen_->CreateUnresolvedFieldLocationSummary(
5793      instruction, instruction->GetFieldType(), calling_convention);
5794}
5795
5796void InstructionCodeGeneratorMIPS64::VisitUnresolvedStaticFieldSet(
5797    HUnresolvedStaticFieldSet* instruction) {
5798  FieldAccessCallingConventionMIPS64 calling_convention;
5799  codegen_->GenerateUnresolvedFieldAccess(instruction,
5800                                          instruction->GetFieldType(),
5801                                          instruction->GetFieldIndex(),
5802                                          instruction->GetDexPc(),
5803                                          calling_convention);
5804}
5805
5806void LocationsBuilderMIPS64::VisitSuspendCheck(HSuspendCheck* instruction) {
5807  LocationSummary* locations =
5808      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
5809  locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
5810}
5811
5812void InstructionCodeGeneratorMIPS64::VisitSuspendCheck(HSuspendCheck* instruction) {
5813  HBasicBlock* block = instruction->GetBlock();
5814  if (block->GetLoopInformation() != nullptr) {
5815    DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5816    // The back edge will generate the suspend check.
5817    return;
5818  }
5819  if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5820    // The goto will generate the suspend check.
5821    return;
5822  }
5823  GenerateSuspendCheck(instruction, nullptr);
5824}
5825
5826void LocationsBuilderMIPS64::VisitThrow(HThrow* instruction) {
5827  LocationSummary* locations =
5828      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
5829  InvokeRuntimeCallingConvention calling_convention;
5830  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5831}
5832
5833void InstructionCodeGeneratorMIPS64::VisitThrow(HThrow* instruction) {
5834  codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
5835  CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5836}
5837
5838void LocationsBuilderMIPS64::VisitTypeConversion(HTypeConversion* conversion) {
5839  Primitive::Type input_type = conversion->GetInputType();
5840  Primitive::Type result_type = conversion->GetResultType();
5841  DCHECK_NE(input_type, result_type);
5842
5843  if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
5844      (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
5845    LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
5846  }
5847
5848  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion);
5849
5850  if (Primitive::IsFloatingPointType(input_type)) {
5851    locations->SetInAt(0, Location::RequiresFpuRegister());
5852  } else {
5853    locations->SetInAt(0, Location::RequiresRegister());
5854  }
5855
5856  if (Primitive::IsFloatingPointType(result_type)) {
5857    locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5858  } else {
5859    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5860  }
5861}
5862
5863void InstructionCodeGeneratorMIPS64::VisitTypeConversion(HTypeConversion* conversion) {
5864  LocationSummary* locations = conversion->GetLocations();
5865  Primitive::Type result_type = conversion->GetResultType();
5866  Primitive::Type input_type = conversion->GetInputType();
5867
5868  DCHECK_NE(input_type, result_type);
5869
5870  if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
5871    GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
5872    GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
5873
5874    switch (result_type) {
5875      case Primitive::kPrimChar:
5876        __ Andi(dst, src, 0xFFFF);
5877        break;
5878      case Primitive::kPrimByte:
5879        if (input_type == Primitive::kPrimLong) {
5880          // Type conversion from long to types narrower than int is a result of code
5881          // transformations. To avoid unpredictable results for SEB and SEH, we first
5882          // need to sign-extend the low 32-bit value into bits 32 through 63.
5883          __ Sll(dst, src, 0);
5884          __ Seb(dst, dst);
5885        } else {
5886          __ Seb(dst, src);
5887        }
5888        break;
5889      case Primitive::kPrimShort:
5890        if (input_type == Primitive::kPrimLong) {
5891          // Type conversion from long to types narrower than int is a result of code
5892          // transformations. To avoid unpredictable results for SEB and SEH, we first
5893          // need to sign-extend the low 32-bit value into bits 32 through 63.
5894          __ Sll(dst, src, 0);
5895          __ Seh(dst, dst);
5896        } else {
5897          __ Seh(dst, src);
5898        }
5899        break;
5900      case Primitive::kPrimInt:
5901      case Primitive::kPrimLong:
5902        // Sign-extend 32-bit int into bits 32 through 63 for int-to-long and long-to-int
5903        // conversions, except when the input and output registers are the same and we are not
5904        // converting longs to shorter types. In these cases, do nothing.
5905        if ((input_type == Primitive::kPrimLong) || (dst != src)) {
5906          __ Sll(dst, src, 0);
5907        }
5908        break;
5909
5910      default:
5911        LOG(FATAL) << "Unexpected type conversion from " << input_type
5912                   << " to " << result_type;
5913    }
5914  } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
5915    FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
5916    GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
5917    if (input_type == Primitive::kPrimLong) {
5918      __ Dmtc1(src, FTMP);
5919      if (result_type == Primitive::kPrimFloat) {
5920        __ Cvtsl(dst, FTMP);
5921      } else {
5922        __ Cvtdl(dst, FTMP);
5923      }
5924    } else {
5925      __ Mtc1(src, FTMP);
5926      if (result_type == Primitive::kPrimFloat) {
5927        __ Cvtsw(dst, FTMP);
5928      } else {
5929        __ Cvtdw(dst, FTMP);
5930      }
5931    }
5932  } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
5933    CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
5934    GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
5935    FpuRegister src = locations->InAt(0).AsFpuRegister<FpuRegister>();
5936    Mips64Label truncate;
5937    Mips64Label done;
5938
5939    // When NAN2008=0 (R2 and before), the truncate instruction produces the maximum positive
5940    // value when the input is either a NaN or is outside of the range of the output type
5941    // after the truncation. IOW, the three special cases (NaN, too small, too big) produce
5942    // the same result.
5943    //
5944    // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
5945    // value of the output type if the input is outside of the range after the truncation or
5946    // produces 0 when the input is a NaN. IOW, the three special cases produce three distinct
5947    // results. This matches the desired float/double-to-int/long conversion exactly.
5948    //
5949    // So, NAN2008 affects handling of negative values and NaNs by the truncate instruction.
5950    //
5951    // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
5952    // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
5953    // even though it must be NAN2008=1 on R6.
5954    //
5955    // The code takes care of the different behaviors by first comparing the input to the
5956    // minimum output value (-2**-63 for truncating to long, -2**-31 for truncating to int).
5957    // If the input is greater than or equal to the minimum, it procedes to the truncate
5958    // instruction, which will handle such an input the same way irrespective of NAN2008.
5959    // Otherwise the input is compared to itself to determine whether it is a NaN or not
5960    // in order to return either zero or the minimum value.
5961    //
5962    // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
5963    // truncate instruction for MIPS64R6.
5964    if (input_type == Primitive::kPrimFloat) {
5965      uint32_t min_val = (result_type == Primitive::kPrimLong)
5966          ? bit_cast<uint32_t, float>(std::numeric_limits<int64_t>::min())
5967          : bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
5968      __ LoadConst32(TMP, min_val);
5969      __ Mtc1(TMP, FTMP);
5970      __ CmpLeS(FTMP, FTMP, src);
5971    } else {
5972      uint64_t min_val = (result_type == Primitive::kPrimLong)
5973          ? bit_cast<uint64_t, double>(std::numeric_limits<int64_t>::min())
5974          : bit_cast<uint64_t, double>(std::numeric_limits<int32_t>::min());
5975      __ LoadConst64(TMP, min_val);
5976      __ Dmtc1(TMP, FTMP);
5977      __ CmpLeD(FTMP, FTMP, src);
5978    }
5979
5980    __ Bc1nez(FTMP, &truncate);
5981
5982    if (input_type == Primitive::kPrimFloat) {
5983      __ CmpEqS(FTMP, src, src);
5984    } else {
5985      __ CmpEqD(FTMP, src, src);
5986    }
5987    if (result_type == Primitive::kPrimLong) {
5988      __ LoadConst64(dst, std::numeric_limits<int64_t>::min());
5989    } else {
5990      __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
5991    }
5992    __ Mfc1(TMP, FTMP);
5993    __ And(dst, dst, TMP);
5994
5995    __ Bc(&done);
5996
5997    __ Bind(&truncate);
5998
5999    if (result_type == Primitive::kPrimLong) {
6000      if (input_type == Primitive::kPrimFloat) {
6001        __ TruncLS(FTMP, src);
6002      } else {
6003        __ TruncLD(FTMP, src);
6004      }
6005      __ Dmfc1(dst, FTMP);
6006    } else {
6007      if (input_type == Primitive::kPrimFloat) {
6008        __ TruncWS(FTMP, src);
6009      } else {
6010        __ TruncWD(FTMP, src);
6011      }
6012      __ Mfc1(dst, FTMP);
6013    }
6014
6015    __ Bind(&done);
6016  } else if (Primitive::IsFloatingPointType(result_type) &&
6017             Primitive::IsFloatingPointType(input_type)) {
6018    FpuRegister dst = locations->Out().AsFpuRegister<FpuRegister>();
6019    FpuRegister src = locations->InAt(0).AsFpuRegister<FpuRegister>();
6020    if (result_type == Primitive::kPrimFloat) {
6021      __ Cvtsd(dst, src);
6022    } else {
6023      __ Cvtds(dst, src);
6024    }
6025  } else {
6026    LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
6027                << " to " << result_type;
6028  }
6029}
6030
6031void LocationsBuilderMIPS64::VisitUShr(HUShr* ushr) {
6032  HandleShift(ushr);
6033}
6034
6035void InstructionCodeGeneratorMIPS64::VisitUShr(HUShr* ushr) {
6036  HandleShift(ushr);
6037}
6038
6039void LocationsBuilderMIPS64::VisitXor(HXor* instruction) {
6040  HandleBinaryOp(instruction);
6041}
6042
6043void InstructionCodeGeneratorMIPS64::VisitXor(HXor* instruction) {
6044  HandleBinaryOp(instruction);
6045}
6046
6047void LocationsBuilderMIPS64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6048  // Nothing to do, this should be removed during prepare for register allocator.
6049  LOG(FATAL) << "Unreachable";
6050}
6051
6052void InstructionCodeGeneratorMIPS64::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6053  // Nothing to do, this should be removed during prepare for register allocator.
6054  LOG(FATAL) << "Unreachable";
6055}
6056
6057void LocationsBuilderMIPS64::VisitEqual(HEqual* comp) {
6058  HandleCondition(comp);
6059}
6060
6061void InstructionCodeGeneratorMIPS64::VisitEqual(HEqual* comp) {
6062  HandleCondition(comp);
6063}
6064
6065void LocationsBuilderMIPS64::VisitNotEqual(HNotEqual* comp) {
6066  HandleCondition(comp);
6067}
6068
6069void InstructionCodeGeneratorMIPS64::VisitNotEqual(HNotEqual* comp) {
6070  HandleCondition(comp);
6071}
6072
6073void LocationsBuilderMIPS64::VisitLessThan(HLessThan* comp) {
6074  HandleCondition(comp);
6075}
6076
6077void InstructionCodeGeneratorMIPS64::VisitLessThan(HLessThan* comp) {
6078  HandleCondition(comp);
6079}
6080
6081void LocationsBuilderMIPS64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
6082  HandleCondition(comp);
6083}
6084
6085void InstructionCodeGeneratorMIPS64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
6086  HandleCondition(comp);
6087}
6088
6089void LocationsBuilderMIPS64::VisitGreaterThan(HGreaterThan* comp) {
6090  HandleCondition(comp);
6091}
6092
6093void InstructionCodeGeneratorMIPS64::VisitGreaterThan(HGreaterThan* comp) {
6094  HandleCondition(comp);
6095}
6096
6097void LocationsBuilderMIPS64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
6098  HandleCondition(comp);
6099}
6100
6101void InstructionCodeGeneratorMIPS64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
6102  HandleCondition(comp);
6103}
6104
6105void LocationsBuilderMIPS64::VisitBelow(HBelow* comp) {
6106  HandleCondition(comp);
6107}
6108
6109void InstructionCodeGeneratorMIPS64::VisitBelow(HBelow* comp) {
6110  HandleCondition(comp);
6111}
6112
6113void LocationsBuilderMIPS64::VisitBelowOrEqual(HBelowOrEqual* comp) {
6114  HandleCondition(comp);
6115}
6116
6117void InstructionCodeGeneratorMIPS64::VisitBelowOrEqual(HBelowOrEqual* comp) {
6118  HandleCondition(comp);
6119}
6120
6121void LocationsBuilderMIPS64::VisitAbove(HAbove* comp) {
6122  HandleCondition(comp);
6123}
6124
6125void InstructionCodeGeneratorMIPS64::VisitAbove(HAbove* comp) {
6126  HandleCondition(comp);
6127}
6128
6129void LocationsBuilderMIPS64::VisitAboveOrEqual(HAboveOrEqual* comp) {
6130  HandleCondition(comp);
6131}
6132
6133void InstructionCodeGeneratorMIPS64::VisitAboveOrEqual(HAboveOrEqual* comp) {
6134  HandleCondition(comp);
6135}
6136
6137// Simple implementation of packed switch - generate cascaded compare/jumps.
6138void LocationsBuilderMIPS64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6139  LocationSummary* locations =
6140      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6141  locations->SetInAt(0, Location::RequiresRegister());
6142}
6143
6144void InstructionCodeGeneratorMIPS64::GenPackedSwitchWithCompares(GpuRegister value_reg,
6145                                                                 int32_t lower_bound,
6146                                                                 uint32_t num_entries,
6147                                                                 HBasicBlock* switch_block,
6148                                                                 HBasicBlock* default_block) {
6149  // Create a set of compare/jumps.
6150  GpuRegister temp_reg = TMP;
6151  __ Addiu32(temp_reg, value_reg, -lower_bound);
6152  // Jump to default if index is negative
6153  // Note: We don't check the case that index is positive while value < lower_bound, because in
6154  // this case, index >= num_entries must be true. So that we can save one branch instruction.
6155  __ Bltzc(temp_reg, codegen_->GetLabelOf(default_block));
6156
6157  const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
6158  // Jump to successors[0] if value == lower_bound.
6159  __ Beqzc(temp_reg, codegen_->GetLabelOf(successors[0]));
6160  int32_t last_index = 0;
6161  for (; num_entries - last_index > 2; last_index += 2) {
6162    __ Addiu(temp_reg, temp_reg, -2);
6163    // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6164    __ Bltzc(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
6165    // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6166    __ Beqzc(temp_reg, codegen_->GetLabelOf(successors[last_index + 2]));
6167  }
6168  if (num_entries - last_index == 2) {
6169    // The last missing case_value.
6170    __ Addiu(temp_reg, temp_reg, -1);
6171    __ Beqzc(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
6172  }
6173
6174  // And the default for any other value.
6175  if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
6176    __ Bc(codegen_->GetLabelOf(default_block));
6177  }
6178}
6179
6180void InstructionCodeGeneratorMIPS64::GenTableBasedPackedSwitch(GpuRegister value_reg,
6181                                                               int32_t lower_bound,
6182                                                               uint32_t num_entries,
6183                                                               HBasicBlock* switch_block,
6184                                                               HBasicBlock* default_block) {
6185  // Create a jump table.
6186  std::vector<Mips64Label*> labels(num_entries);
6187  const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
6188  for (uint32_t i = 0; i < num_entries; i++) {
6189    labels[i] = codegen_->GetLabelOf(successors[i]);
6190  }
6191  JumpTable* table = __ CreateJumpTable(std::move(labels));
6192
6193  // Is the value in range?
6194  __ Addiu32(TMP, value_reg, -lower_bound);
6195  __ LoadConst32(AT, num_entries);
6196  __ Bgeuc(TMP, AT, codegen_->GetLabelOf(default_block));
6197
6198  // We are in the range of the table.
6199  // Load the target address from the jump table, indexing by the value.
6200  __ LoadLabelAddress(AT, table->GetLabel());
6201  __ Dlsa(TMP, TMP, AT, 2);
6202  __ Lw(TMP, TMP, 0);
6203  // Compute the absolute target address by adding the table start address
6204  // (the table contains offsets to targets relative to its start).
6205  __ Daddu(TMP, TMP, AT);
6206  // And jump.
6207  __ Jr(TMP);
6208  __ Nop();
6209}
6210
6211void InstructionCodeGeneratorMIPS64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6212  int32_t lower_bound = switch_instr->GetStartValue();
6213  uint32_t num_entries = switch_instr->GetNumEntries();
6214  LocationSummary* locations = switch_instr->GetLocations();
6215  GpuRegister value_reg = locations->InAt(0).AsRegister<GpuRegister>();
6216  HBasicBlock* switch_block = switch_instr->GetBlock();
6217  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
6218
6219  if (num_entries > kPackedSwitchJumpTableThreshold) {
6220    GenTableBasedPackedSwitch(value_reg,
6221                              lower_bound,
6222                              num_entries,
6223                              switch_block,
6224                              default_block);
6225  } else {
6226    GenPackedSwitchWithCompares(value_reg,
6227                                lower_bound,
6228                                num_entries,
6229                                switch_block,
6230                                default_block);
6231  }
6232}
6233
6234void LocationsBuilderMIPS64::VisitClassTableGet(HClassTableGet* instruction) {
6235  LocationSummary* locations =
6236      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6237  locations->SetInAt(0, Location::RequiresRegister());
6238  locations->SetOut(Location::RequiresRegister());
6239}
6240
6241void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet* instruction) {
6242  LocationSummary* locations = instruction->GetLocations();
6243  if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
6244    uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
6245        instruction->GetIndex(), kMips64PointerSize).SizeValue();
6246    __ LoadFromOffset(kLoadDoubleword,
6247                      locations->Out().AsRegister<GpuRegister>(),
6248                      locations->InAt(0).AsRegister<GpuRegister>(),
6249                      method_offset);
6250  } else {
6251    uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
6252        instruction->GetIndex(), kMips64PointerSize));
6253    __ LoadFromOffset(kLoadDoubleword,
6254                      locations->Out().AsRegister<GpuRegister>(),
6255                      locations->InAt(0).AsRegister<GpuRegister>(),
6256                      mirror::Class::ImtPtrOffset(kMips64PointerSize).Uint32Value());
6257    __ LoadFromOffset(kLoadDoubleword,
6258                      locations->Out().AsRegister<GpuRegister>(),
6259                      locations->Out().AsRegister<GpuRegister>(),
6260                      method_offset);
6261  }
6262}
6263
6264}  // namespace mips64
6265}  // namespace art
6266