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