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 "intrinsics_mips64.h"
     18 
     19 #include "arch/mips64/instruction_set_features_mips64.h"
     20 #include "art_method.h"
     21 #include "code_generator_mips64.h"
     22 #include "entrypoints/quick/quick_entrypoints.h"
     23 #include "heap_poisoning.h"
     24 #include "intrinsics.h"
     25 #include "mirror/array-inl.h"
     26 #include "mirror/object_array-inl.h"
     27 #include "mirror/string.h"
     28 #include "scoped_thread_state_change-inl.h"
     29 #include "thread.h"
     30 #include "utils/mips64/assembler_mips64.h"
     31 #include "utils/mips64/constants_mips64.h"
     32 
     33 namespace art {
     34 
     35 namespace mips64 {
     36 
     37 IntrinsicLocationsBuilderMIPS64::IntrinsicLocationsBuilderMIPS64(CodeGeneratorMIPS64* codegen)
     38   : codegen_(codegen), allocator_(codegen->GetGraph()->GetAllocator()) {
     39 }
     40 
     41 Mips64Assembler* IntrinsicCodeGeneratorMIPS64::GetAssembler() {
     42   return reinterpret_cast<Mips64Assembler*>(codegen_->GetAssembler());
     43 }
     44 
     45 ArenaAllocator* IntrinsicCodeGeneratorMIPS64::GetAllocator() {
     46   return codegen_->GetGraph()->GetAllocator();
     47 }
     48 
     49 #define __ codegen->GetAssembler()->
     50 
     51 static void MoveFromReturnRegister(Location trg,
     52                                    DataType::Type type,
     53                                    CodeGeneratorMIPS64* codegen) {
     54   if (!trg.IsValid()) {
     55     DCHECK_EQ(type, DataType::Type::kVoid);
     56     return;
     57   }
     58 
     59   DCHECK_NE(type, DataType::Type::kVoid);
     60 
     61   if (DataType::IsIntegralType(type) || type == DataType::Type::kReference) {
     62     GpuRegister trg_reg = trg.AsRegister<GpuRegister>();
     63     if (trg_reg != V0) {
     64       __ Move(V0, trg_reg);
     65     }
     66   } else {
     67     FpuRegister trg_reg = trg.AsFpuRegister<FpuRegister>();
     68     if (trg_reg != F0) {
     69       if (type == DataType::Type::kFloat32) {
     70         __ MovS(F0, trg_reg);
     71       } else {
     72         __ MovD(F0, trg_reg);
     73       }
     74     }
     75   }
     76 }
     77 
     78 static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS64* codegen) {
     79   InvokeDexCallingConventionVisitorMIPS64 calling_convention_visitor;
     80   IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
     81 }
     82 
     83 // Slow-path for fallback (calling the managed code to handle the
     84 // intrinsic) in an intrinsified call. This will copy the arguments
     85 // into the positions for a regular call.
     86 //
     87 // Note: The actual parameters are required to be in the locations
     88 //       given by the invoke's location summary. If an intrinsic
     89 //       modifies those locations before a slowpath call, they must be
     90 //       restored!
     91 class IntrinsicSlowPathMIPS64 : public SlowPathCodeMIPS64 {
     92  public:
     93   explicit IntrinsicSlowPathMIPS64(HInvoke* invoke)
     94      : SlowPathCodeMIPS64(invoke), invoke_(invoke) { }
     95 
     96   void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
     97     CodeGeneratorMIPS64* codegen = down_cast<CodeGeneratorMIPS64*>(codegen_in);
     98 
     99     __ Bind(GetEntryLabel());
    100 
    101     SaveLiveRegisters(codegen, invoke_->GetLocations());
    102 
    103     MoveArguments(invoke_, codegen);
    104 
    105     if (invoke_->IsInvokeStaticOrDirect()) {
    106       codegen->GenerateStaticOrDirectCall(
    107           invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(A0), this);
    108     } else {
    109       codegen->GenerateVirtualCall(
    110           invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0), this);
    111     }
    112 
    113     // Copy the result back to the expected output.
    114     Location out = invoke_->GetLocations()->Out();
    115     if (out.IsValid()) {
    116       DCHECK(out.IsRegister());  // TODO: Replace this when we support output in memory.
    117       DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
    118       MoveFromReturnRegister(out, invoke_->GetType(), codegen);
    119     }
    120 
    121     RestoreLiveRegisters(codegen, invoke_->GetLocations());
    122     __ Bc(GetExitLabel());
    123   }
    124 
    125   const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS64"; }
    126 
    127  private:
    128   // The instruction where this slow path is happening.
    129   HInvoke* const invoke_;
    130 
    131   DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS64);
    132 };
    133 
    134 #undef __
    135 
    136 bool IntrinsicLocationsBuilderMIPS64::TryDispatch(HInvoke* invoke) {
    137   Dispatch(invoke);
    138   LocationSummary* res = invoke->GetLocations();
    139   return res != nullptr && res->Intrinsified();
    140 }
    141 
    142 #define __ assembler->
    143 
    144 static void CreateFPToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
    145   LocationSummary* locations =
    146       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    147   locations->SetInAt(0, Location::RequiresFpuRegister());
    148   locations->SetOut(Location::RequiresRegister());
    149 }
    150 
    151 static void MoveFPToInt(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
    152   FpuRegister in  = locations->InAt(0).AsFpuRegister<FpuRegister>();
    153   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    154 
    155   if (is64bit) {
    156     __ Dmfc1(out, in);
    157   } else {
    158     __ Mfc1(out, in);
    159   }
    160 }
    161 
    162 // long java.lang.Double.doubleToRawLongBits(double)
    163 void IntrinsicLocationsBuilderMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
    164   CreateFPToIntLocations(allocator_, invoke);
    165 }
    166 
    167 void IntrinsicCodeGeneratorMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
    168   MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    169 }
    170 
    171 // int java.lang.Float.floatToRawIntBits(float)
    172 void IntrinsicLocationsBuilderMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
    173   CreateFPToIntLocations(allocator_, invoke);
    174 }
    175 
    176 void IntrinsicCodeGeneratorMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
    177   MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    178 }
    179 
    180 static void CreateIntToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
    181   LocationSummary* locations =
    182       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    183   locations->SetInAt(0, Location::RequiresRegister());
    184   locations->SetOut(Location::RequiresFpuRegister());
    185 }
    186 
    187 static void MoveIntToFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
    188   GpuRegister in  = locations->InAt(0).AsRegister<GpuRegister>();
    189   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
    190 
    191   if (is64bit) {
    192     __ Dmtc1(in, out);
    193   } else {
    194     __ Mtc1(in, out);
    195   }
    196 }
    197 
    198 // double java.lang.Double.longBitsToDouble(long)
    199 void IntrinsicLocationsBuilderMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
    200   CreateIntToFPLocations(allocator_, invoke);
    201 }
    202 
    203 void IntrinsicCodeGeneratorMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
    204   MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    205 }
    206 
    207 // float java.lang.Float.intBitsToFloat(int)
    208 void IntrinsicLocationsBuilderMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
    209   CreateIntToFPLocations(allocator_, invoke);
    210 }
    211 
    212 void IntrinsicCodeGeneratorMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
    213   MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    214 }
    215 
    216 static void CreateIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
    217   LocationSummary* locations =
    218       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    219   locations->SetInAt(0, Location::RequiresRegister());
    220   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
    221 }
    222 
    223 static void GenReverseBytes(LocationSummary* locations,
    224                             DataType::Type type,
    225                             Mips64Assembler* assembler) {
    226   GpuRegister in  = locations->InAt(0).AsRegister<GpuRegister>();
    227   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    228 
    229   switch (type) {
    230     case DataType::Type::kInt16:
    231       __ Dsbh(out, in);
    232       __ Seh(out, out);
    233       break;
    234     case DataType::Type::kInt32:
    235       __ Rotr(out, in, 16);
    236       __ Wsbh(out, out);
    237       break;
    238     case DataType::Type::kInt64:
    239       __ Dsbh(out, in);
    240       __ Dshd(out, out);
    241       break;
    242     default:
    243       LOG(FATAL) << "Unexpected size for reverse-bytes: " << type;
    244       UNREACHABLE();
    245   }
    246 }
    247 
    248 // int java.lang.Integer.reverseBytes(int)
    249 void IntrinsicLocationsBuilderMIPS64::VisitIntegerReverseBytes(HInvoke* invoke) {
    250   CreateIntToIntLocations(allocator_, invoke);
    251 }
    252 
    253 void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverseBytes(HInvoke* invoke) {
    254   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
    255 }
    256 
    257 // long java.lang.Long.reverseBytes(long)
    258 void IntrinsicLocationsBuilderMIPS64::VisitLongReverseBytes(HInvoke* invoke) {
    259   CreateIntToIntLocations(allocator_, invoke);
    260 }
    261 
    262 void IntrinsicCodeGeneratorMIPS64::VisitLongReverseBytes(HInvoke* invoke) {
    263   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
    264 }
    265 
    266 // short java.lang.Short.reverseBytes(short)
    267 void IntrinsicLocationsBuilderMIPS64::VisitShortReverseBytes(HInvoke* invoke) {
    268   CreateIntToIntLocations(allocator_, invoke);
    269 }
    270 
    271 void IntrinsicCodeGeneratorMIPS64::VisitShortReverseBytes(HInvoke* invoke) {
    272   GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler());
    273 }
    274 
    275 static void GenNumberOfLeadingZeroes(LocationSummary* locations,
    276                                      bool is64bit,
    277                                      Mips64Assembler* assembler) {
    278   GpuRegister in  = locations->InAt(0).AsRegister<GpuRegister>();
    279   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    280 
    281   if (is64bit) {
    282     __ Dclz(out, in);
    283   } else {
    284     __ Clz(out, in);
    285   }
    286 }
    287 
    288 // int java.lang.Integer.numberOfLeadingZeros(int i)
    289 void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
    290   CreateIntToIntLocations(allocator_, invoke);
    291 }
    292 
    293 void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
    294   GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    295 }
    296 
    297 // int java.lang.Long.numberOfLeadingZeros(long i)
    298 void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
    299   CreateIntToIntLocations(allocator_, invoke);
    300 }
    301 
    302 void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
    303   GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    304 }
    305 
    306 static void GenNumberOfTrailingZeroes(LocationSummary* locations,
    307                                       bool is64bit,
    308                                       Mips64Assembler* assembler) {
    309   Location in = locations->InAt(0);
    310   Location out = locations->Out();
    311 
    312   if (is64bit) {
    313     __ Dsbh(out.AsRegister<GpuRegister>(), in.AsRegister<GpuRegister>());
    314     __ Dshd(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
    315     __ Dbitswap(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
    316     __ Dclz(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
    317   } else {
    318     __ Rotr(out.AsRegister<GpuRegister>(), in.AsRegister<GpuRegister>(), 16);
    319     __ Wsbh(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
    320     __ Bitswap(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
    321     __ Clz(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
    322   }
    323 }
    324 
    325 // int java.lang.Integer.numberOfTrailingZeros(int i)
    326 void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
    327   CreateIntToIntLocations(allocator_, invoke);
    328 }
    329 
    330 void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
    331   GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    332 }
    333 
    334 // int java.lang.Long.numberOfTrailingZeros(long i)
    335 void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
    336   CreateIntToIntLocations(allocator_, invoke);
    337 }
    338 
    339 void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
    340   GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    341 }
    342 
    343 static void GenReverse(LocationSummary* locations,
    344                        DataType::Type type,
    345                        Mips64Assembler* assembler) {
    346   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
    347 
    348   GpuRegister in  = locations->InAt(0).AsRegister<GpuRegister>();
    349   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    350 
    351   if (type == DataType::Type::kInt32) {
    352     __ Rotr(out, in, 16);
    353     __ Wsbh(out, out);
    354     __ Bitswap(out, out);
    355   } else {
    356     __ Dsbh(out, in);
    357     __ Dshd(out, out);
    358     __ Dbitswap(out, out);
    359   }
    360 }
    361 
    362 // int java.lang.Integer.reverse(int)
    363 void IntrinsicLocationsBuilderMIPS64::VisitIntegerReverse(HInvoke* invoke) {
    364   CreateIntToIntLocations(allocator_, invoke);
    365 }
    366 
    367 void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverse(HInvoke* invoke) {
    368   GenReverse(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
    369 }
    370 
    371 // long java.lang.Long.reverse(long)
    372 void IntrinsicLocationsBuilderMIPS64::VisitLongReverse(HInvoke* invoke) {
    373   CreateIntToIntLocations(allocator_, invoke);
    374 }
    375 
    376 void IntrinsicCodeGeneratorMIPS64::VisitLongReverse(HInvoke* invoke) {
    377   GenReverse(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
    378 }
    379 
    380 static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
    381   LocationSummary* locations =
    382       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    383   locations->SetInAt(0, Location::RequiresFpuRegister());
    384   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    385 }
    386 
    387 static void GenBitCount(LocationSummary* locations,
    388                         const DataType::Type type,
    389                         Mips64Assembler* assembler) {
    390   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    391   GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
    392 
    393   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
    394 
    395   // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
    396   //
    397   // A generalization of the best bit counting method to integers of
    398   // bit-widths up to 128 (parameterized by type T) is this:
    399   //
    400   // v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
    401   // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
    402   // v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
    403   // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; // count
    404   //
    405   // For comparison, for 32-bit quantities, this algorithm can be executed
    406   // using 20 MIPS instructions (the calls to LoadConst32() generate two
    407   // machine instructions each for the values being used in this algorithm).
    408   // A(n unrolled) loop-based algorithm requires 25 instructions.
    409   //
    410   // For a 64-bit operand this can be performed in 24 instructions compared
    411   // to a(n unrolled) loop based algorithm which requires 38 instructions.
    412   //
    413   // There are algorithms which are faster in the cases where very few
    414   // bits are set but the algorithm here attempts to minimize the total
    415   // number of instructions executed even when a large number of bits
    416   // are set.
    417 
    418   if (type == DataType::Type::kInt32) {
    419     __ Srl(TMP, in, 1);
    420     __ LoadConst32(AT, 0x55555555);
    421     __ And(TMP, TMP, AT);
    422     __ Subu(TMP, in, TMP);
    423     __ LoadConst32(AT, 0x33333333);
    424     __ And(out, TMP, AT);
    425     __ Srl(TMP, TMP, 2);
    426     __ And(TMP, TMP, AT);
    427     __ Addu(TMP, out, TMP);
    428     __ Srl(out, TMP, 4);
    429     __ Addu(out, out, TMP);
    430     __ LoadConst32(AT, 0x0F0F0F0F);
    431     __ And(out, out, AT);
    432     __ LoadConst32(TMP, 0x01010101);
    433     __ MulR6(out, out, TMP);
    434     __ Srl(out, out, 24);
    435   } else if (type == DataType::Type::kInt64) {
    436     __ Dsrl(TMP, in, 1);
    437     __ LoadConst64(AT, 0x5555555555555555L);
    438     __ And(TMP, TMP, AT);
    439     __ Dsubu(TMP, in, TMP);
    440     __ LoadConst64(AT, 0x3333333333333333L);
    441     __ And(out, TMP, AT);
    442     __ Dsrl(TMP, TMP, 2);
    443     __ And(TMP, TMP, AT);
    444     __ Daddu(TMP, out, TMP);
    445     __ Dsrl(out, TMP, 4);
    446     __ Daddu(out, out, TMP);
    447     __ LoadConst64(AT, 0x0F0F0F0F0F0F0F0FL);
    448     __ And(out, out, AT);
    449     __ LoadConst64(TMP, 0x0101010101010101L);
    450     __ Dmul(out, out, TMP);
    451     __ Dsrl32(out, out, 24);
    452   }
    453 }
    454 
    455 // int java.lang.Integer.bitCount(int)
    456 void IntrinsicLocationsBuilderMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
    457   CreateIntToIntLocations(allocator_, invoke);
    458 }
    459 
    460 void IntrinsicCodeGeneratorMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
    461   GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
    462 }
    463 
    464 // int java.lang.Long.bitCount(long)
    465 void IntrinsicLocationsBuilderMIPS64::VisitLongBitCount(HInvoke* invoke) {
    466   CreateIntToIntLocations(allocator_, invoke);
    467 }
    468 
    469 void IntrinsicCodeGeneratorMIPS64::VisitLongBitCount(HInvoke* invoke) {
    470   GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
    471 }
    472 
    473 static void MathAbsFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
    474   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
    475   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
    476 
    477   if (is64bit) {
    478     __ AbsD(out, in);
    479   } else {
    480     __ AbsS(out, in);
    481   }
    482 }
    483 
    484 // double java.lang.Math.abs(double)
    485 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsDouble(HInvoke* invoke) {
    486   CreateFPToFPLocations(allocator_, invoke);
    487 }
    488 
    489 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsDouble(HInvoke* invoke) {
    490   MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    491 }
    492 
    493 // float java.lang.Math.abs(float)
    494 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsFloat(HInvoke* invoke) {
    495   CreateFPToFPLocations(allocator_, invoke);
    496 }
    497 
    498 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsFloat(HInvoke* invoke) {
    499   MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    500 }
    501 
    502 static void CreateIntToInt(ArenaAllocator* allocator, HInvoke* invoke) {
    503   LocationSummary* locations =
    504       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    505   locations->SetInAt(0, Location::RequiresRegister());
    506   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
    507 }
    508 
    509 static void GenAbsInteger(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
    510   GpuRegister in  = locations->InAt(0).AsRegister<GpuRegister>();
    511   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    512 
    513   if (is64bit) {
    514     __ Dsra32(AT, in, 31);
    515     __ Xor(out, in, AT);
    516     __ Dsubu(out, out, AT);
    517   } else {
    518     __ Sra(AT, in, 31);
    519     __ Xor(out, in, AT);
    520     __ Subu(out, out, AT);
    521   }
    522 }
    523 
    524 // int java.lang.Math.abs(int)
    525 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsInt(HInvoke* invoke) {
    526   CreateIntToInt(allocator_, invoke);
    527 }
    528 
    529 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsInt(HInvoke* invoke) {
    530   GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    531 }
    532 
    533 // long java.lang.Math.abs(long)
    534 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsLong(HInvoke* invoke) {
    535   CreateIntToInt(allocator_, invoke);
    536 }
    537 
    538 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsLong(HInvoke* invoke) {
    539   GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    540 }
    541 
    542 static void GenMinMaxFP(LocationSummary* locations,
    543                         bool is_min,
    544                         DataType::Type type,
    545                         Mips64Assembler* assembler) {
    546   FpuRegister a = locations->InAt(0).AsFpuRegister<FpuRegister>();
    547   FpuRegister b = locations->InAt(1).AsFpuRegister<FpuRegister>();
    548   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
    549 
    550   Mips64Label noNaNs;
    551   Mips64Label done;
    552   FpuRegister ftmp = ((out != a) && (out != b)) ? out : FTMP;
    553 
    554   // When Java computes min/max it prefers a NaN to a number; the
    555   // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of
    556   // the inputs is a NaN and the other is a valid number, the MIPS
    557   // instruction will return the number; Java wants the NaN value
    558   // returned. This is why there is extra logic preceding the use of
    559   // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
    560   // NaN, return the NaN, otherwise return the min/max.
    561   if (type == DataType::Type::kFloat64) {
    562     __ CmpUnD(FTMP, a, b);
    563     __ Bc1eqz(FTMP, &noNaNs);
    564 
    565     // One of the inputs is a NaN
    566     __ CmpEqD(ftmp, a, a);
    567     // If a == a then b is the NaN, otherwise a is the NaN.
    568     __ SelD(ftmp, a, b);
    569 
    570     if (ftmp != out) {
    571       __ MovD(out, ftmp);
    572     }
    573 
    574     __ Bc(&done);
    575 
    576     __ Bind(&noNaNs);
    577 
    578     if (is_min) {
    579       __ MinD(out, a, b);
    580     } else {
    581       __ MaxD(out, a, b);
    582     }
    583   } else {
    584     DCHECK_EQ(type, DataType::Type::kFloat32);
    585     __ CmpUnS(FTMP, a, b);
    586     __ Bc1eqz(FTMP, &noNaNs);
    587 
    588     // One of the inputs is a NaN
    589     __ CmpEqS(ftmp, a, a);
    590     // If a == a then b is the NaN, otherwise a is the NaN.
    591     __ SelS(ftmp, a, b);
    592 
    593     if (ftmp != out) {
    594       __ MovS(out, ftmp);
    595     }
    596 
    597     __ Bc(&done);
    598 
    599     __ Bind(&noNaNs);
    600 
    601     if (is_min) {
    602       __ MinS(out, a, b);
    603     } else {
    604       __ MaxS(out, a, b);
    605     }
    606   }
    607 
    608   __ Bind(&done);
    609 }
    610 
    611 static void CreateFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) {
    612   LocationSummary* locations =
    613       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    614   locations->SetInAt(0, Location::RequiresFpuRegister());
    615   locations->SetInAt(1, Location::RequiresFpuRegister());
    616   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    617 }
    618 
    619 // double java.lang.Math.min(double, double)
    620 void IntrinsicLocationsBuilderMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) {
    621   CreateFPFPToFPLocations(allocator_, invoke);
    622 }
    623 
    624 void IntrinsicCodeGeneratorMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) {
    625   GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, DataType::Type::kFloat64, GetAssembler());
    626 }
    627 
    628 // float java.lang.Math.min(float, float)
    629 void IntrinsicLocationsBuilderMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) {
    630   CreateFPFPToFPLocations(allocator_, invoke);
    631 }
    632 
    633 void IntrinsicCodeGeneratorMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) {
    634   GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, DataType::Type::kFloat32, GetAssembler());
    635 }
    636 
    637 // double java.lang.Math.max(double, double)
    638 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
    639   CreateFPFPToFPLocations(allocator_, invoke);
    640 }
    641 
    642 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
    643   GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, DataType::Type::kFloat64, GetAssembler());
    644 }
    645 
    646 // float java.lang.Math.max(float, float)
    647 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) {
    648   CreateFPFPToFPLocations(allocator_, invoke);
    649 }
    650 
    651 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) {
    652   GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, DataType::Type::kFloat32, GetAssembler());
    653 }
    654 
    655 static void GenMinMax(LocationSummary* locations,
    656                       bool is_min,
    657                       Mips64Assembler* assembler) {
    658   GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
    659   GpuRegister rhs = locations->InAt(1).AsRegister<GpuRegister>();
    660   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    661 
    662   if (lhs == rhs) {
    663     if (out != lhs) {
    664       __ Move(out, lhs);
    665     }
    666   } else {
    667     // Some architectures, such as ARM and MIPS (prior to r6), have a
    668     // conditional move instruction which only changes the target
    669     // (output) register if the condition is true (MIPS prior to r6 had
    670     // MOVF, MOVT, and MOVZ). The SELEQZ and SELNEZ instructions always
    671     // change the target (output) register.  If the condition is true the
    672     // output register gets the contents of the "rs" register; otherwise,
    673     // the output register is set to zero. One consequence of this is
    674     // that to implement something like "rd = c==0 ? rs : rt" MIPS64r6
    675     // needs to use a pair of SELEQZ/SELNEZ instructions.  After
    676     // executing this pair of instructions one of the output registers
    677     // from the pair will necessarily contain zero. Then the code ORs the
    678     // output registers from the SELEQZ/SELNEZ instructions to get the
    679     // final result.
    680     //
    681     // The initial test to see if the output register is same as the
    682     // first input register is needed to make sure that value in the
    683     // first input register isn't clobbered before we've finished
    684     // computing the output value. The logic in the corresponding else
    685     // clause performs the same task but makes sure the second input
    686     // register isn't clobbered in the event that it's the same register
    687     // as the output register; the else clause also handles the case
    688     // where the output register is distinct from both the first, and the
    689     // second input registers.
    690     if (out == lhs) {
    691       __ Slt(AT, rhs, lhs);
    692       if (is_min) {
    693         __ Seleqz(out, lhs, AT);
    694         __ Selnez(AT, rhs, AT);
    695       } else {
    696         __ Selnez(out, lhs, AT);
    697         __ Seleqz(AT, rhs, AT);
    698       }
    699     } else {
    700       __ Slt(AT, lhs, rhs);
    701       if (is_min) {
    702         __ Seleqz(out, rhs, AT);
    703         __ Selnez(AT, lhs, AT);
    704       } else {
    705         __ Selnez(out, rhs, AT);
    706         __ Seleqz(AT, lhs, AT);
    707       }
    708     }
    709     __ Or(out, out, AT);
    710   }
    711 }
    712 
    713 static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) {
    714   LocationSummary* locations =
    715       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    716   locations->SetInAt(0, Location::RequiresRegister());
    717   locations->SetInAt(1, Location::RequiresRegister());
    718   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
    719 }
    720 
    721 // int java.lang.Math.min(int, int)
    722 void IntrinsicLocationsBuilderMIPS64::VisitMathMinIntInt(HInvoke* invoke) {
    723   CreateIntIntToIntLocations(allocator_, invoke);
    724 }
    725 
    726 void IntrinsicCodeGeneratorMIPS64::VisitMathMinIntInt(HInvoke* invoke) {
    727   GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler());
    728 }
    729 
    730 // long java.lang.Math.min(long, long)
    731 void IntrinsicLocationsBuilderMIPS64::VisitMathMinLongLong(HInvoke* invoke) {
    732   CreateIntIntToIntLocations(allocator_, invoke);
    733 }
    734 
    735 void IntrinsicCodeGeneratorMIPS64::VisitMathMinLongLong(HInvoke* invoke) {
    736   GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler());
    737 }
    738 
    739 // int java.lang.Math.max(int, int)
    740 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxIntInt(HInvoke* invoke) {
    741   CreateIntIntToIntLocations(allocator_, invoke);
    742 }
    743 
    744 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxIntInt(HInvoke* invoke) {
    745   GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler());
    746 }
    747 
    748 // long java.lang.Math.max(long, long)
    749 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxLongLong(HInvoke* invoke) {
    750   CreateIntIntToIntLocations(allocator_, invoke);
    751 }
    752 
    753 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxLongLong(HInvoke* invoke) {
    754   GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler());
    755 }
    756 
    757 // double java.lang.Math.sqrt(double)
    758 void IntrinsicLocationsBuilderMIPS64::VisitMathSqrt(HInvoke* invoke) {
    759   CreateFPToFPLocations(allocator_, invoke);
    760 }
    761 
    762 void IntrinsicCodeGeneratorMIPS64::VisitMathSqrt(HInvoke* invoke) {
    763   LocationSummary* locations = invoke->GetLocations();
    764   Mips64Assembler* assembler = GetAssembler();
    765   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
    766   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
    767 
    768   __ SqrtD(out, in);
    769 }
    770 
    771 static void CreateFPToFP(ArenaAllocator* allocator,
    772                          HInvoke* invoke,
    773                          Location::OutputOverlap overlaps = Location::kOutputOverlap) {
    774   LocationSummary* locations =
    775       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    776   locations->SetInAt(0, Location::RequiresFpuRegister());
    777   locations->SetOut(Location::RequiresFpuRegister(), overlaps);
    778 }
    779 
    780 // double java.lang.Math.rint(double)
    781 void IntrinsicLocationsBuilderMIPS64::VisitMathRint(HInvoke* invoke) {
    782   CreateFPToFP(allocator_, invoke, Location::kNoOutputOverlap);
    783 }
    784 
    785 void IntrinsicCodeGeneratorMIPS64::VisitMathRint(HInvoke* invoke) {
    786   LocationSummary* locations = invoke->GetLocations();
    787   Mips64Assembler* assembler = GetAssembler();
    788   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
    789   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
    790 
    791   __ RintD(out, in);
    792 }
    793 
    794 // double java.lang.Math.floor(double)
    795 void IntrinsicLocationsBuilderMIPS64::VisitMathFloor(HInvoke* invoke) {
    796   CreateFPToFP(allocator_, invoke);
    797 }
    798 
    799 const constexpr uint16_t kFPLeaveUnchanged = kPositiveZero |
    800                                              kPositiveInfinity |
    801                                              kNegativeZero |
    802                                              kNegativeInfinity |
    803                                              kQuietNaN |
    804                                              kSignalingNaN;
    805 
    806 enum FloatRoundingMode {
    807   kFloor,
    808   kCeil,
    809 };
    810 
    811 static void GenRoundingMode(LocationSummary* locations,
    812                             FloatRoundingMode mode,
    813                             Mips64Assembler* assembler) {
    814   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
    815   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
    816 
    817   DCHECK_NE(in, out);
    818 
    819   Mips64Label done;
    820 
    821   // double floor/ceil(double in) {
    822   //     if in.isNaN || in.isInfinite || in.isZero {
    823   //         return in;
    824   //     }
    825   __ ClassD(out, in);
    826   __ Dmfc1(AT, out);
    827   __ Andi(AT, AT, kFPLeaveUnchanged);   // +0.0 | +Inf | -0.0 | -Inf | qNaN | sNaN
    828   __ MovD(out, in);
    829   __ Bnezc(AT, &done);
    830 
    831   //     Long outLong = floor/ceil(in);
    832   //     if (outLong == Long.MAX_VALUE) || (outLong == Long.MIN_VALUE) {
    833   //         // floor()/ceil() has almost certainly returned a value
    834   //         // which can't be successfully represented as a signed
    835   //         // 64-bit number.  Java expects that the input value will
    836   //         // be returned in these cases.
    837   //         // There is also a small probability that floor(in)/ceil(in)
    838   //         // correctly truncates/rounds up the input value to
    839   //         // Long.MAX_VALUE or Long.MIN_VALUE. In these cases, this
    840   //         // exception handling code still does the correct thing.
    841   //         return in;
    842   //     }
    843   if (mode == kFloor) {
    844     __ FloorLD(out, in);
    845   } else  if (mode == kCeil) {
    846     __ CeilLD(out, in);
    847   }
    848   __ Dmfc1(AT, out);
    849   __ MovD(out, in);
    850   __ Daddiu(TMP, AT, 1);
    851   __ Dati(TMP, 0x8000);  // TMP = AT + 0x8000 0000 0000 0001
    852                          // or    AT - 0x7FFF FFFF FFFF FFFF.
    853                          // IOW, TMP = 1 if AT = Long.MIN_VALUE
    854                          // or   TMP = 0 if AT = Long.MAX_VALUE.
    855   __ Dsrl(TMP, TMP, 1);  // TMP = 0 if AT = Long.MIN_VALUE
    856                          //         or AT = Long.MAX_VALUE.
    857   __ Beqzc(TMP, &done);
    858 
    859   //     double out = outLong;
    860   //     return out;
    861   __ Dmtc1(AT, out);
    862   __ Cvtdl(out, out);
    863   __ Bind(&done);
    864   // }
    865 }
    866 
    867 void IntrinsicCodeGeneratorMIPS64::VisitMathFloor(HInvoke* invoke) {
    868   GenRoundingMode(invoke->GetLocations(), kFloor, GetAssembler());
    869 }
    870 
    871 // double java.lang.Math.ceil(double)
    872 void IntrinsicLocationsBuilderMIPS64::VisitMathCeil(HInvoke* invoke) {
    873   CreateFPToFP(allocator_, invoke);
    874 }
    875 
    876 void IntrinsicCodeGeneratorMIPS64::VisitMathCeil(HInvoke* invoke) {
    877   GenRoundingMode(invoke->GetLocations(), kCeil, GetAssembler());
    878 }
    879 
    880 static void GenRound(LocationSummary* locations, Mips64Assembler* assembler, DataType::Type type) {
    881   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
    882   FpuRegister half = locations->GetTemp(0).AsFpuRegister<FpuRegister>();
    883   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
    884 
    885   DCHECK(type == DataType::Type::kFloat32 || type == DataType::Type::kFloat64);
    886 
    887   Mips64Label done;
    888 
    889   // out = floor(in);
    890   //
    891   // if (out != MAX_VALUE && out != MIN_VALUE) {
    892   //   TMP = ((in - out) >= 0.5) ? 1 : 0;
    893   //   return out += TMP;
    894   // }
    895   // return out;
    896 
    897   // out = floor(in);
    898   if (type == DataType::Type::kFloat64) {
    899     __ FloorLD(FTMP, in);
    900     __ Dmfc1(out, FTMP);
    901   } else {
    902     __ FloorWS(FTMP, in);
    903     __ Mfc1(out, FTMP);
    904   }
    905 
    906   // if (out != MAX_VALUE && out != MIN_VALUE)
    907   if (type == DataType::Type::kFloat64) {
    908     __ Daddiu(TMP, out, 1);
    909     __ Dati(TMP, 0x8000);  // TMP = out + 0x8000 0000 0000 0001
    910                            // or    out - 0x7FFF FFFF FFFF FFFF.
    911                            // IOW, TMP = 1 if out = Long.MIN_VALUE
    912                            // or   TMP = 0 if out = Long.MAX_VALUE.
    913     __ Dsrl(TMP, TMP, 1);  // TMP = 0 if out = Long.MIN_VALUE
    914                            //         or out = Long.MAX_VALUE.
    915     __ Beqzc(TMP, &done);
    916   } else {
    917     __ Addiu(TMP, out, 1);
    918     __ Aui(TMP, TMP, 0x8000);  // TMP = out + 0x8000 0001
    919                                // or    out - 0x7FFF FFFF.
    920                                // IOW, TMP = 1 if out = Int.MIN_VALUE
    921                                // or   TMP = 0 if out = Int.MAX_VALUE.
    922     __ Srl(TMP, TMP, 1);       // TMP = 0 if out = Int.MIN_VALUE
    923                                //         or out = Int.MAX_VALUE.
    924     __ Beqzc(TMP, &done);
    925   }
    926 
    927   // TMP = (0.5 <= (in - out)) ? -1 : 0;
    928   if (type == DataType::Type::kFloat64) {
    929     __ Cvtdl(FTMP, FTMP);  // Convert output of floor.l.d back to "double".
    930     __ LoadConst64(AT, bit_cast<int64_t, double>(0.5));
    931     __ SubD(FTMP, in, FTMP);
    932     __ Dmtc1(AT, half);
    933     __ CmpLeD(FTMP, half, FTMP);
    934     __ Dmfc1(TMP, FTMP);
    935   } else {
    936     __ Cvtsw(FTMP, FTMP);  // Convert output of floor.w.s back to "float".
    937     __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
    938     __ SubS(FTMP, in, FTMP);
    939     __ Mtc1(AT, half);
    940     __ CmpLeS(FTMP, half, FTMP);
    941     __ Mfc1(TMP, FTMP);
    942   }
    943 
    944   // Return out -= TMP.
    945   if (type == DataType::Type::kFloat64) {
    946     __ Dsubu(out, out, TMP);
    947   } else {
    948     __ Subu(out, out, TMP);
    949   }
    950 
    951   __ Bind(&done);
    952 }
    953 
    954 // int java.lang.Math.round(float)
    955 void IntrinsicLocationsBuilderMIPS64::VisitMathRoundFloat(HInvoke* invoke) {
    956   LocationSummary* locations =
    957       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    958   locations->SetInAt(0, Location::RequiresFpuRegister());
    959   locations->AddTemp(Location::RequiresFpuRegister());
    960   locations->SetOut(Location::RequiresRegister());
    961 }
    962 
    963 void IntrinsicCodeGeneratorMIPS64::VisitMathRoundFloat(HInvoke* invoke) {
    964   GenRound(invoke->GetLocations(), GetAssembler(), DataType::Type::kFloat32);
    965 }
    966 
    967 // long java.lang.Math.round(double)
    968 void IntrinsicLocationsBuilderMIPS64::VisitMathRoundDouble(HInvoke* invoke) {
    969   LocationSummary* locations =
    970       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
    971   locations->SetInAt(0, Location::RequiresFpuRegister());
    972   locations->AddTemp(Location::RequiresFpuRegister());
    973   locations->SetOut(Location::RequiresRegister());
    974 }
    975 
    976 void IntrinsicCodeGeneratorMIPS64::VisitMathRoundDouble(HInvoke* invoke) {
    977   GenRound(invoke->GetLocations(), GetAssembler(), DataType::Type::kFloat64);
    978 }
    979 
    980 // byte libcore.io.Memory.peekByte(long address)
    981 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekByte(HInvoke* invoke) {
    982   CreateIntToIntLocations(allocator_, invoke);
    983 }
    984 
    985 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekByte(HInvoke* invoke) {
    986   Mips64Assembler* assembler = GetAssembler();
    987   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
    988   GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
    989 
    990   __ Lb(out, adr, 0);
    991 }
    992 
    993 // short libcore.io.Memory.peekShort(long address)
    994 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekShortNative(HInvoke* invoke) {
    995   CreateIntToIntLocations(allocator_, invoke);
    996 }
    997 
    998 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekShortNative(HInvoke* invoke) {
    999   Mips64Assembler* assembler = GetAssembler();
   1000   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
   1001   GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
   1002 
   1003   __ Lh(out, adr, 0);
   1004 }
   1005 
   1006 // int libcore.io.Memory.peekInt(long address)
   1007 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekIntNative(HInvoke* invoke) {
   1008   CreateIntToIntLocations(allocator_, invoke);
   1009 }
   1010 
   1011 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekIntNative(HInvoke* invoke) {
   1012   Mips64Assembler* assembler = GetAssembler();
   1013   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
   1014   GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
   1015 
   1016   __ Lw(out, adr, 0);
   1017 }
   1018 
   1019 // long libcore.io.Memory.peekLong(long address)
   1020 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekLongNative(HInvoke* invoke) {
   1021   CreateIntToIntLocations(allocator_, invoke);
   1022 }
   1023 
   1024 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekLongNative(HInvoke* invoke) {
   1025   Mips64Assembler* assembler = GetAssembler();
   1026   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
   1027   GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
   1028 
   1029   __ Ld(out, adr, 0);
   1030 }
   1031 
   1032 static void CreateIntIntToVoidLocations(ArenaAllocator* allocator, HInvoke* invoke) {
   1033   LocationSummary* locations =
   1034       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   1035   locations->SetInAt(0, Location::RequiresRegister());
   1036   locations->SetInAt(1, Location::RequiresRegister());
   1037 }
   1038 
   1039 // void libcore.io.Memory.pokeByte(long address, byte value)
   1040 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeByte(HInvoke* invoke) {
   1041   CreateIntIntToVoidLocations(allocator_, invoke);
   1042 }
   1043 
   1044 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeByte(HInvoke* invoke) {
   1045   Mips64Assembler* assembler = GetAssembler();
   1046   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
   1047   GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
   1048 
   1049   __ Sb(val, adr, 0);
   1050 }
   1051 
   1052 // void libcore.io.Memory.pokeShort(long address, short value)
   1053 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeShortNative(HInvoke* invoke) {
   1054   CreateIntIntToVoidLocations(allocator_, invoke);
   1055 }
   1056 
   1057 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeShortNative(HInvoke* invoke) {
   1058   Mips64Assembler* assembler = GetAssembler();
   1059   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
   1060   GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
   1061 
   1062   __ Sh(val, adr, 0);
   1063 }
   1064 
   1065 // void libcore.io.Memory.pokeInt(long address, int value)
   1066 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeIntNative(HInvoke* invoke) {
   1067   CreateIntIntToVoidLocations(allocator_, invoke);
   1068 }
   1069 
   1070 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeIntNative(HInvoke* invoke) {
   1071   Mips64Assembler* assembler = GetAssembler();
   1072   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
   1073   GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
   1074 
   1075   __ Sw(val, adr, 00);
   1076 }
   1077 
   1078 // void libcore.io.Memory.pokeLong(long address, long value)
   1079 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeLongNative(HInvoke* invoke) {
   1080   CreateIntIntToVoidLocations(allocator_, invoke);
   1081 }
   1082 
   1083 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeLongNative(HInvoke* invoke) {
   1084   Mips64Assembler* assembler = GetAssembler();
   1085   GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
   1086   GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
   1087 
   1088   __ Sd(val, adr, 0);
   1089 }
   1090 
   1091 // Thread java.lang.Thread.currentThread()
   1092 void IntrinsicLocationsBuilderMIPS64::VisitThreadCurrentThread(HInvoke* invoke) {
   1093   LocationSummary* locations =
   1094       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   1095   locations->SetOut(Location::RequiresRegister());
   1096 }
   1097 
   1098 void IntrinsicCodeGeneratorMIPS64::VisitThreadCurrentThread(HInvoke* invoke) {
   1099   Mips64Assembler* assembler = GetAssembler();
   1100   GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
   1101 
   1102   __ LoadFromOffset(kLoadUnsignedWord,
   1103                     out,
   1104                     TR,
   1105                     Thread::PeerOffset<kMips64PointerSize>().Int32Value());
   1106 }
   1107 
   1108 static void CreateIntIntIntToIntLocations(ArenaAllocator* allocator,
   1109                                           HInvoke* invoke,
   1110                                           DataType::Type type) {
   1111   bool can_call = kEmitCompilerReadBarrier &&
   1112       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
   1113        invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
   1114   LocationSummary* locations =
   1115       new (allocator) LocationSummary(invoke,
   1116                                       can_call
   1117                                           ? LocationSummary::kCallOnSlowPath
   1118                                           : LocationSummary::kNoCall,
   1119                                       kIntrinsified);
   1120   if (can_call && kUseBakerReadBarrier) {
   1121     locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty());  // No caller-save registers.
   1122   }
   1123   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   1124   locations->SetInAt(1, Location::RequiresRegister());
   1125   locations->SetInAt(2, Location::RequiresRegister());
   1126   locations->SetOut(Location::RequiresRegister(),
   1127                     (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
   1128   if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   1129     // We need a temporary register for the read barrier marking slow
   1130     // path in InstructionCodeGeneratorMIPS64::GenerateReferenceLoadWithBakerReadBarrier.
   1131     locations->AddTemp(Location::RequiresRegister());
   1132   }
   1133 }
   1134 
   1135 // Note that the caller must supply a properly aligned memory address.
   1136 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
   1137 static void GenUnsafeGet(HInvoke* invoke,
   1138                          DataType::Type type,
   1139                          bool is_volatile,
   1140                          CodeGeneratorMIPS64* codegen) {
   1141   LocationSummary* locations = invoke->GetLocations();
   1142   DCHECK((type == DataType::Type::kInt32) ||
   1143          (type == DataType::Type::kInt64) ||
   1144          (type == DataType::Type::kReference)) << type;
   1145   Mips64Assembler* assembler = codegen->GetAssembler();
   1146   // Target register.
   1147   Location trg_loc = locations->Out();
   1148   GpuRegister trg = trg_loc.AsRegister<GpuRegister>();
   1149   // Object pointer.
   1150   Location base_loc = locations->InAt(1);
   1151   GpuRegister base = base_loc.AsRegister<GpuRegister>();
   1152   // Long offset.
   1153   Location offset_loc = locations->InAt(2);
   1154   GpuRegister offset = offset_loc.AsRegister<GpuRegister>();
   1155 
   1156   if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == DataType::Type::kReference))) {
   1157     __ Daddu(TMP, base, offset);
   1158   }
   1159 
   1160   switch (type) {
   1161     case DataType::Type::kInt64:
   1162       __ Ld(trg, TMP, 0);
   1163       if (is_volatile) {
   1164         __ Sync(0);
   1165       }
   1166       break;
   1167 
   1168     case DataType::Type::kInt32:
   1169       __ Lw(trg, TMP, 0);
   1170       if (is_volatile) {
   1171         __ Sync(0);
   1172       }
   1173       break;
   1174 
   1175     case DataType::Type::kReference:
   1176       if (kEmitCompilerReadBarrier) {
   1177         if (kUseBakerReadBarrier) {
   1178           Location temp = locations->GetTemp(0);
   1179           codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
   1180                                                              trg_loc,
   1181                                                              base,
   1182                                                              /* offset */ 0U,
   1183                                                              /* index */ offset_loc,
   1184                                                              TIMES_1,
   1185                                                              temp,
   1186                                                              /* needs_null_check */ false);
   1187           if (is_volatile) {
   1188             __ Sync(0);
   1189           }
   1190         } else {
   1191           __ Lwu(trg, TMP, 0);
   1192           if (is_volatile) {
   1193             __ Sync(0);
   1194           }
   1195           codegen->GenerateReadBarrierSlow(invoke,
   1196                                            trg_loc,
   1197                                            trg_loc,
   1198                                            base_loc,
   1199                                            /* offset */ 0U,
   1200                                            /* index */ offset_loc);
   1201         }
   1202       } else {
   1203         __ Lwu(trg, TMP, 0);
   1204         if (is_volatile) {
   1205           __ Sync(0);
   1206         }
   1207         __ MaybeUnpoisonHeapReference(trg);
   1208       }
   1209       break;
   1210 
   1211     default:
   1212       LOG(FATAL) << "Unsupported op size " << type;
   1213       UNREACHABLE();
   1214   }
   1215 }
   1216 
   1217 // int sun.misc.Unsafe.getInt(Object o, long offset)
   1218 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGet(HInvoke* invoke) {
   1219   CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt32);
   1220 }
   1221 
   1222 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGet(HInvoke* invoke) {
   1223   GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ false, codegen_);
   1224 }
   1225 
   1226 // int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
   1227 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
   1228   CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt32);
   1229 }
   1230 
   1231 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
   1232   GenUnsafeGet(invoke, DataType::Type::kInt32, /* is_volatile */ true, codegen_);
   1233 }
   1234 
   1235 // long sun.misc.Unsafe.getLong(Object o, long offset)
   1236 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
   1237   CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt64);
   1238 }
   1239 
   1240 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
   1241   GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ false, codegen_);
   1242 }
   1243 
   1244 // long sun.misc.Unsafe.getLongVolatile(Object o, long offset)
   1245 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
   1246   CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kInt64);
   1247 }
   1248 
   1249 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
   1250   GenUnsafeGet(invoke, DataType::Type::kInt64, /* is_volatile */ true, codegen_);
   1251 }
   1252 
   1253 // Object sun.misc.Unsafe.getObject(Object o, long offset)
   1254 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
   1255   CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kReference);
   1256 }
   1257 
   1258 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
   1259   GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ false, codegen_);
   1260 }
   1261 
   1262 // Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
   1263 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   1264   CreateIntIntIntToIntLocations(allocator_, invoke, DataType::Type::kReference);
   1265 }
   1266 
   1267 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   1268   GenUnsafeGet(invoke, DataType::Type::kReference, /* is_volatile */ true, codegen_);
   1269 }
   1270 
   1271 static void CreateIntIntIntIntToVoid(ArenaAllocator* allocator, HInvoke* invoke) {
   1272   LocationSummary* locations =
   1273       new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   1274   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   1275   locations->SetInAt(1, Location::RequiresRegister());
   1276   locations->SetInAt(2, Location::RequiresRegister());
   1277   locations->SetInAt(3, Location::RequiresRegister());
   1278 }
   1279 
   1280 // Note that the caller must supply a properly aligned memory address.
   1281 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
   1282 static void GenUnsafePut(LocationSummary* locations,
   1283                          DataType::Type type,
   1284                          bool is_volatile,
   1285                          bool is_ordered,
   1286                          CodeGeneratorMIPS64* codegen) {
   1287   DCHECK((type == DataType::Type::kInt32) ||
   1288          (type == DataType::Type::kInt64) ||
   1289          (type == DataType::Type::kReference));
   1290   Mips64Assembler* assembler = codegen->GetAssembler();
   1291   // Object pointer.
   1292   GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
   1293   // Long offset.
   1294   GpuRegister offset = locations->InAt(2).AsRegister<GpuRegister>();
   1295   GpuRegister value = locations->InAt(3).AsRegister<GpuRegister>();
   1296 
   1297   __ Daddu(TMP, base, offset);
   1298   if (is_volatile || is_ordered) {
   1299     __ Sync(0);
   1300   }
   1301   switch (type) {
   1302     case DataType::Type::kInt32:
   1303     case DataType::Type::kReference:
   1304       if (kPoisonHeapReferences && type == DataType::Type::kReference) {
   1305         __ PoisonHeapReference(AT, value);
   1306         __ Sw(AT, TMP, 0);
   1307       } else {
   1308         __ Sw(value, TMP, 0);
   1309       }
   1310       break;
   1311 
   1312     case DataType::Type::kInt64:
   1313       __ Sd(value, TMP, 0);
   1314       break;
   1315 
   1316     default:
   1317       LOG(FATAL) << "Unsupported op size " << type;
   1318       UNREACHABLE();
   1319   }
   1320   if (is_volatile) {
   1321     __ Sync(0);
   1322   }
   1323 
   1324   if (type == DataType::Type::kReference) {
   1325     bool value_can_be_null = true;  // TODO: Worth finding out this information?
   1326     codegen->MarkGCCard(base, value, value_can_be_null);
   1327   }
   1328 }
   1329 
   1330 // void sun.misc.Unsafe.putInt(Object o, long offset, int x)
   1331 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePut(HInvoke* invoke) {
   1332   CreateIntIntIntIntToVoid(allocator_, invoke);
   1333 }
   1334 
   1335 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePut(HInvoke* invoke) {
   1336   GenUnsafePut(invoke->GetLocations(),
   1337                DataType::Type::kInt32,
   1338                /* is_volatile */ false,
   1339                /* is_ordered */ false,
   1340                codegen_);
   1341 }
   1342 
   1343 // void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x)
   1344 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) {
   1345   CreateIntIntIntIntToVoid(allocator_, invoke);
   1346 }
   1347 
   1348 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) {
   1349   GenUnsafePut(invoke->GetLocations(),
   1350                DataType::Type::kInt32,
   1351                /* is_volatile */ false,
   1352                /* is_ordered */ true,
   1353                codegen_);
   1354 }
   1355 
   1356 // void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x)
   1357 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) {
   1358   CreateIntIntIntIntToVoid(allocator_, invoke);
   1359 }
   1360 
   1361 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) {
   1362   GenUnsafePut(invoke->GetLocations(),
   1363                DataType::Type::kInt32,
   1364                /* is_volatile */ true,
   1365                /* is_ordered */ false,
   1366                codegen_);
   1367 }
   1368 
   1369 // void sun.misc.Unsafe.putObject(Object o, long offset, Object x)
   1370 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObject(HInvoke* invoke) {
   1371   CreateIntIntIntIntToVoid(allocator_, invoke);
   1372 }
   1373 
   1374 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObject(HInvoke* invoke) {
   1375   GenUnsafePut(invoke->GetLocations(),
   1376                DataType::Type::kReference,
   1377                /* is_volatile */ false,
   1378                /* is_ordered */ false,
   1379                codegen_);
   1380 }
   1381 
   1382 // void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x)
   1383 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   1384   CreateIntIntIntIntToVoid(allocator_, invoke);
   1385 }
   1386 
   1387 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   1388   GenUnsafePut(invoke->GetLocations(),
   1389                DataType::Type::kReference,
   1390                /* is_volatile */ false,
   1391                /* is_ordered */ true,
   1392                codegen_);
   1393 }
   1394 
   1395 // void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x)
   1396 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   1397   CreateIntIntIntIntToVoid(allocator_, invoke);
   1398 }
   1399 
   1400 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   1401   GenUnsafePut(invoke->GetLocations(),
   1402                DataType::Type::kReference,
   1403                /* is_volatile */ true,
   1404                /* is_ordered */ false,
   1405                codegen_);
   1406 }
   1407 
   1408 // void sun.misc.Unsafe.putLong(Object o, long offset, long x)
   1409 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLong(HInvoke* invoke) {
   1410   CreateIntIntIntIntToVoid(allocator_, invoke);
   1411 }
   1412 
   1413 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLong(HInvoke* invoke) {
   1414   GenUnsafePut(invoke->GetLocations(),
   1415                DataType::Type::kInt64,
   1416                /* is_volatile */ false,
   1417                /* is_ordered */ false,
   1418                codegen_);
   1419 }
   1420 
   1421 // void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x)
   1422 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   1423   CreateIntIntIntIntToVoid(allocator_, invoke);
   1424 }
   1425 
   1426 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   1427   GenUnsafePut(invoke->GetLocations(),
   1428                DataType::Type::kInt64,
   1429                /* is_volatile */ false,
   1430                /* is_ordered */ true,
   1431                codegen_);
   1432 }
   1433 
   1434 // void sun.misc.Unsafe.putLongVolatile(Object o, long offset, long x)
   1435 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   1436   CreateIntIntIntIntToVoid(allocator_, invoke);
   1437 }
   1438 
   1439 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
   1440   GenUnsafePut(invoke->GetLocations(),
   1441                DataType::Type::kInt64,
   1442                /* is_volatile */ true,
   1443                /* is_ordered */ false,
   1444                codegen_);
   1445 }
   1446 
   1447 static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* allocator, HInvoke* invoke) {
   1448   bool can_call = kEmitCompilerReadBarrier &&
   1449       kUseBakerReadBarrier &&
   1450       (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
   1451   LocationSummary* locations =
   1452       new (allocator) LocationSummary(invoke,
   1453                                       can_call
   1454                                           ? LocationSummary::kCallOnSlowPath
   1455                                           : LocationSummary::kNoCall,
   1456                                       kIntrinsified);
   1457   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   1458   locations->SetInAt(1, Location::RequiresRegister());
   1459   locations->SetInAt(2, Location::RequiresRegister());
   1460   locations->SetInAt(3, Location::RequiresRegister());
   1461   locations->SetInAt(4, Location::RequiresRegister());
   1462   locations->SetOut(Location::RequiresRegister());
   1463 
   1464   // Temporary register used in CAS by (Baker) read barrier.
   1465   if (can_call) {
   1466     locations->AddTemp(Location::RequiresRegister());
   1467   }
   1468 }
   1469 
   1470 // Note that the caller must supply a properly aligned memory address.
   1471 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
   1472 static void GenCas(HInvoke* invoke, DataType::Type type, CodeGeneratorMIPS64* codegen) {
   1473   Mips64Assembler* assembler = codegen->GetAssembler();
   1474   LocationSummary* locations = invoke->GetLocations();
   1475   GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
   1476   Location offset_loc = locations->InAt(2);
   1477   GpuRegister offset = offset_loc.AsRegister<GpuRegister>();
   1478   GpuRegister expected = locations->InAt(3).AsRegister<GpuRegister>();
   1479   GpuRegister value = locations->InAt(4).AsRegister<GpuRegister>();
   1480   Location out_loc = locations->Out();
   1481   GpuRegister out = out_loc.AsRegister<GpuRegister>();
   1482 
   1483   DCHECK_NE(base, out);
   1484   DCHECK_NE(offset, out);
   1485   DCHECK_NE(expected, out);
   1486 
   1487   if (type == DataType::Type::kReference) {
   1488     // The only read barrier implementation supporting the
   1489     // UnsafeCASObject intrinsic is the Baker-style read barriers.
   1490     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
   1491 
   1492     // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
   1493     // object and scan the receiver at the next GC for nothing.
   1494     bool value_can_be_null = true;  // TODO: Worth finding out this information?
   1495     codegen->MarkGCCard(base, value, value_can_be_null);
   1496 
   1497     if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   1498       Location temp = locations->GetTemp(0);
   1499       // Need to make sure the reference stored in the field is a to-space
   1500       // one before attempting the CAS or the CAS could fail incorrectly.
   1501       codegen->GenerateReferenceLoadWithBakerReadBarrier(
   1502           invoke,
   1503           out_loc,  // Unused, used only as a "temporary" within the read barrier.
   1504           base,
   1505           /* offset */ 0u,
   1506           /* index */ offset_loc,
   1507           ScaleFactor::TIMES_1,
   1508           temp,
   1509           /* needs_null_check */ false,
   1510           /* always_update_field */ true);
   1511     }
   1512   }
   1513 
   1514   Mips64Label loop_head, exit_loop;
   1515   __ Daddu(TMP, base, offset);
   1516 
   1517   if (kPoisonHeapReferences && type == DataType::Type::kReference) {
   1518     __ PoisonHeapReference(expected);
   1519     // Do not poison `value`, if it is the same register as
   1520     // `expected`, which has just been poisoned.
   1521     if (value != expected) {
   1522       __ PoisonHeapReference(value);
   1523     }
   1524   }
   1525 
   1526   // do {
   1527   //   tmp_value = [tmp_ptr] - expected;
   1528   // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
   1529   // result = tmp_value != 0;
   1530 
   1531   __ Sync(0);
   1532   __ Bind(&loop_head);
   1533   if (type == DataType::Type::kInt64) {
   1534     __ Lld(out, TMP);
   1535   } else {
   1536     // Note: We will need a read barrier here, when read barrier
   1537     // support is added to the MIPS64 back end.
   1538     __ Ll(out, TMP);
   1539     if (type == DataType::Type::kReference) {
   1540       // The LL instruction sign-extends the 32-bit value, but
   1541       // 32-bit references must be zero-extended. Zero-extend `out`.
   1542       __ Dext(out, out, 0, 32);
   1543     }
   1544   }
   1545   __ Dsubu(out, out, expected);         // If we didn't get the 'expected'
   1546   __ Sltiu(out, out, 1);                // value, set 'out' to false, and
   1547   __ Beqzc(out, &exit_loop);            // return.
   1548   __ Move(out, value);  // Use 'out' for the 'store conditional' instruction.
   1549                         // If we use 'value' directly, we would lose 'value'
   1550                         // in the case that the store fails.  Whether the
   1551                         // store succeeds, or fails, it will load the
   1552                         // correct Boolean value into the 'out' register.
   1553   if (type == DataType::Type::kInt64) {
   1554     __ Scd(out, TMP);
   1555   } else {
   1556     __ Sc(out, TMP);
   1557   }
   1558   __ Beqzc(out, &loop_head);    // If we couldn't do the read-modify-write
   1559                                 // cycle atomically then retry.
   1560   __ Bind(&exit_loop);
   1561   __ Sync(0);
   1562 
   1563   if (kPoisonHeapReferences && type == DataType::Type::kReference) {
   1564     __ UnpoisonHeapReference(expected);
   1565     // Do not unpoison `value`, if it is the same register as
   1566     // `expected`, which has just been unpoisoned.
   1567     if (value != expected) {
   1568       __ UnpoisonHeapReference(value);
   1569     }
   1570   }
   1571 }
   1572 
   1573 // boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
   1574 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASInt(HInvoke* invoke) {
   1575   CreateIntIntIntIntIntToIntPlusTemps(allocator_, invoke);
   1576 }
   1577 
   1578 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASInt(HInvoke* invoke) {
   1579   GenCas(invoke, DataType::Type::kInt32, codegen_);
   1580 }
   1581 
   1582 // boolean sun.misc.Unsafe.compareAndSwapLong(Object o, long offset, long expected, long x)
   1583 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASLong(HInvoke* invoke) {
   1584   CreateIntIntIntIntIntToIntPlusTemps(allocator_, invoke);
   1585 }
   1586 
   1587 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASLong(HInvoke* invoke) {
   1588   GenCas(invoke, DataType::Type::kInt64, codegen_);
   1589 }
   1590 
   1591 // boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
   1592 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASObject(HInvoke* invoke) {
   1593   // The only read barrier implementation supporting the
   1594   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   1595   if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) {
   1596     return;
   1597   }
   1598 
   1599   CreateIntIntIntIntIntToIntPlusTemps(allocator_, invoke);
   1600 }
   1601 
   1602 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASObject(HInvoke* invoke) {
   1603   // The only read barrier implementation supporting the
   1604   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   1605   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
   1606 
   1607   GenCas(invoke, DataType::Type::kReference, codegen_);
   1608 }
   1609 
   1610 // int java.lang.String.compareTo(String anotherString)
   1611 void IntrinsicLocationsBuilderMIPS64::VisitStringCompareTo(HInvoke* invoke) {
   1612   LocationSummary* locations = new (allocator_) LocationSummary(
   1613       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
   1614   InvokeRuntimeCallingConvention calling_convention;
   1615   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   1616   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   1617   Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   1618   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
   1619 }
   1620 
   1621 void IntrinsicCodeGeneratorMIPS64::VisitStringCompareTo(HInvoke* invoke) {
   1622   Mips64Assembler* assembler = GetAssembler();
   1623   LocationSummary* locations = invoke->GetLocations();
   1624 
   1625   // Note that the null check must have been done earlier.
   1626   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
   1627 
   1628   GpuRegister argument = locations->InAt(1).AsRegister<GpuRegister>();
   1629   SlowPathCodeMIPS64* slow_path =
   1630       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS64(invoke);
   1631   codegen_->AddSlowPath(slow_path);
   1632   __ Beqzc(argument, slow_path->GetEntryLabel());
   1633 
   1634   codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
   1635   __ Bind(slow_path->GetExitLabel());
   1636 }
   1637 
   1638 // boolean java.lang.String.equals(Object anObject)
   1639 void IntrinsicLocationsBuilderMIPS64::VisitStringEquals(HInvoke* invoke) {
   1640   if (kEmitCompilerReadBarrier &&
   1641       !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
   1642       !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
   1643     // No support for this odd case (String class is moveable, not in the boot image).
   1644     return;
   1645   }
   1646 
   1647   LocationSummary* locations =
   1648       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   1649   locations->SetInAt(0, Location::RequiresRegister());
   1650   locations->SetInAt(1, Location::RequiresRegister());
   1651   locations->SetOut(Location::RequiresRegister());
   1652 
   1653   // Temporary registers to store lengths of strings and for calculations.
   1654   locations->AddTemp(Location::RequiresRegister());
   1655   locations->AddTemp(Location::RequiresRegister());
   1656   locations->AddTemp(Location::RequiresRegister());
   1657 }
   1658 
   1659 void IntrinsicCodeGeneratorMIPS64::VisitStringEquals(HInvoke* invoke) {
   1660   Mips64Assembler* assembler = GetAssembler();
   1661   LocationSummary* locations = invoke->GetLocations();
   1662 
   1663   GpuRegister str = locations->InAt(0).AsRegister<GpuRegister>();
   1664   GpuRegister arg = locations->InAt(1).AsRegister<GpuRegister>();
   1665   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
   1666 
   1667   GpuRegister temp1 = locations->GetTemp(0).AsRegister<GpuRegister>();
   1668   GpuRegister temp2 = locations->GetTemp(1).AsRegister<GpuRegister>();
   1669   GpuRegister temp3 = locations->GetTemp(2).AsRegister<GpuRegister>();
   1670 
   1671   Mips64Label loop;
   1672   Mips64Label end;
   1673   Mips64Label return_true;
   1674   Mips64Label return_false;
   1675 
   1676   // Get offsets of count, value, and class fields within a string object.
   1677   const int32_t count_offset = mirror::String::CountOffset().Int32Value();
   1678   const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
   1679   const int32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   1680 
   1681   // Note that the null check must have been done earlier.
   1682   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
   1683 
   1684   // If the register containing the pointer to "this", and the register
   1685   // containing the pointer to "anObject" are the same register then
   1686   // "this", and "anObject" are the same object and we can
   1687   // short-circuit the logic to a true result.
   1688   if (str == arg) {
   1689     __ LoadConst64(out, 1);
   1690     return;
   1691   }
   1692 
   1693   StringEqualsOptimizations optimizations(invoke);
   1694   if (!optimizations.GetArgumentNotNull()) {
   1695     // Check if input is null, return false if it is.
   1696     __ Beqzc(arg, &return_false);
   1697   }
   1698 
   1699   // Reference equality check, return true if same reference.
   1700   __ Beqc(str, arg, &return_true);
   1701 
   1702   if (!optimizations.GetArgumentIsString()) {
   1703     // Instanceof check for the argument by comparing class fields.
   1704     // All string objects must have the same type since String cannot be subclassed.
   1705     // Receiver must be a string object, so its class field is equal to all strings' class fields.
   1706     // If the argument is a string object, its class field must be equal to receiver's class field.
   1707     __ Lw(temp1, str, class_offset);
   1708     __ Lw(temp2, arg, class_offset);
   1709     __ Bnec(temp1, temp2, &return_false);
   1710   }
   1711 
   1712   // Load `count` fields of this and argument strings.
   1713   __ Lw(temp1, str, count_offset);
   1714   __ Lw(temp2, arg, count_offset);
   1715   // Check if `count` fields are equal, return false if they're not.
   1716   // Also compares the compression style, if differs return false.
   1717   __ Bnec(temp1, temp2, &return_false);
   1718   // Return true if both strings are empty. Even with string compression `count == 0` means empty.
   1719   static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
   1720                 "Expecting 0=compressed, 1=uncompressed");
   1721   __ Beqzc(temp1, &return_true);
   1722 
   1723   // Don't overwrite input registers
   1724   __ Move(TMP, str);
   1725   __ Move(temp3, arg);
   1726 
   1727   // Assertions that must hold in order to compare strings 8 bytes at a time.
   1728   DCHECK_ALIGNED(value_offset, 8);
   1729   static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
   1730 
   1731   if (mirror::kUseStringCompression) {
   1732     // For string compression, calculate the number of bytes to compare (not chars).
   1733     __ Dext(temp2, temp1, 0, 1);         // Extract compression flag.
   1734     __ Srl(temp1, temp1, 1);             // Extract length.
   1735     __ Sllv(temp1, temp1, temp2);        // Double the byte count if uncompressed.
   1736   }
   1737 
   1738   // Loop to compare strings 8 bytes at a time starting at the beginning of the string.
   1739   // Ok to do this because strings are zero-padded to kObjectAlignment.
   1740   __ Bind(&loop);
   1741   __ Ld(out, TMP, value_offset);
   1742   __ Ld(temp2, temp3, value_offset);
   1743   __ Bnec(out, temp2, &return_false);
   1744   __ Daddiu(TMP, TMP, 8);
   1745   __ Daddiu(temp3, temp3, 8);
   1746   // With string compression, we have compared 8 bytes, otherwise 4 chars.
   1747   __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -8 : -4);
   1748   __ Bgtzc(temp1, &loop);
   1749 
   1750   // Return true and exit the function.
   1751   // If loop does not result in returning false, we return true.
   1752   __ Bind(&return_true);
   1753   __ LoadConst64(out, 1);
   1754   __ Bc(&end);
   1755 
   1756   // Return false and exit the function.
   1757   __ Bind(&return_false);
   1758   __ LoadConst64(out, 0);
   1759   __ Bind(&end);
   1760 }
   1761 
   1762 static void GenerateStringIndexOf(HInvoke* invoke,
   1763                                   Mips64Assembler* assembler,
   1764                                   CodeGeneratorMIPS64* codegen,
   1765                                   bool start_at_zero) {
   1766   LocationSummary* locations = invoke->GetLocations();
   1767   GpuRegister tmp_reg = start_at_zero ? locations->GetTemp(0).AsRegister<GpuRegister>() : TMP;
   1768 
   1769   // Note that the null check must have been done earlier.
   1770   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
   1771 
   1772   // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
   1773   // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
   1774   SlowPathCodeMIPS64* slow_path = nullptr;
   1775   HInstruction* code_point = invoke->InputAt(1);
   1776   if (code_point->IsIntConstant()) {
   1777     if (!IsUint<16>(code_point->AsIntConstant()->GetValue())) {
   1778       // Always needs the slow-path. We could directly dispatch to it,
   1779       // but this case should be rare, so for simplicity just put the
   1780       // full slow-path down and branch unconditionally.
   1781       slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathMIPS64(invoke);
   1782       codegen->AddSlowPath(slow_path);
   1783       __ Bc(slow_path->GetEntryLabel());
   1784       __ Bind(slow_path->GetExitLabel());
   1785       return;
   1786     }
   1787   } else if (code_point->GetType() != DataType::Type::kUint16) {
   1788     GpuRegister char_reg = locations->InAt(1).AsRegister<GpuRegister>();
   1789     __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
   1790     slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathMIPS64(invoke);
   1791     codegen->AddSlowPath(slow_path);
   1792     __ Bltuc(tmp_reg, char_reg, slow_path->GetEntryLabel());    // UTF-16 required
   1793   }
   1794 
   1795   if (start_at_zero) {
   1796     DCHECK_EQ(tmp_reg, A2);
   1797     // Start-index = 0.
   1798     __ Clear(tmp_reg);
   1799   }
   1800 
   1801   codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
   1802   CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>();
   1803 
   1804   if (slow_path != nullptr) {
   1805     __ Bind(slow_path->GetExitLabel());
   1806   }
   1807 }
   1808 
   1809 // int java.lang.String.indexOf(int ch)
   1810 void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOf(HInvoke* invoke) {
   1811   LocationSummary* locations = new (allocator_) LocationSummary(
   1812       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
   1813   // We have a hand-crafted assembly stub that follows the runtime
   1814   // calling convention. So it's best to align the inputs accordingly.
   1815   InvokeRuntimeCallingConvention calling_convention;
   1816   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   1817   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   1818   Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   1819   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
   1820 
   1821   // Need a temp for slow-path codepoint compare, and need to send start-index=0.
   1822   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   1823 }
   1824 
   1825 void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOf(HInvoke* invoke) {
   1826   GenerateStringIndexOf(invoke, GetAssembler(), codegen_, /* start_at_zero */ true);
   1827 }
   1828 
   1829 // int java.lang.String.indexOf(int ch, int fromIndex)
   1830 void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
   1831   LocationSummary* locations = new (allocator_) LocationSummary(
   1832       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
   1833   // We have a hand-crafted assembly stub that follows the runtime
   1834   // calling convention. So it's best to align the inputs accordingly.
   1835   InvokeRuntimeCallingConvention calling_convention;
   1836   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   1837   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   1838   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   1839   Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   1840   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
   1841 }
   1842 
   1843 void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
   1844   GenerateStringIndexOf(invoke, GetAssembler(), codegen_, /* start_at_zero */ false);
   1845 }
   1846 
   1847 // java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
   1848 void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
   1849   LocationSummary* locations = new (allocator_) LocationSummary(
   1850       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
   1851   InvokeRuntimeCallingConvention calling_convention;
   1852   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   1853   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   1854   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   1855   locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
   1856   Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   1857   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
   1858 }
   1859 
   1860 void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
   1861   Mips64Assembler* assembler = GetAssembler();
   1862   LocationSummary* locations = invoke->GetLocations();
   1863 
   1864   GpuRegister byte_array = locations->InAt(0).AsRegister<GpuRegister>();
   1865   SlowPathCodeMIPS64* slow_path =
   1866       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS64(invoke);
   1867   codegen_->AddSlowPath(slow_path);
   1868   __ Beqzc(byte_array, slow_path->GetEntryLabel());
   1869 
   1870   codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
   1871   CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
   1872   __ Bind(slow_path->GetExitLabel());
   1873 }
   1874 
   1875 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
   1876 void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) {
   1877   LocationSummary* locations =
   1878       new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
   1879   InvokeRuntimeCallingConvention calling_convention;
   1880   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   1881   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   1882   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   1883   Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   1884   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
   1885 }
   1886 
   1887 void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) {
   1888   // No need to emit code checking whether `locations->InAt(2)` is a null
   1889   // pointer, as callers of the native method
   1890   //
   1891   //   java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
   1892   //
   1893   // all include a null check on `data` before calling that method.
   1894   codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
   1895   CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
   1896 }
   1897 
   1898 // java.lang.StringFactory.newStringFromString(String toCopy)
   1899 void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
   1900   LocationSummary* locations = new (allocator_) LocationSummary(
   1901       invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified);
   1902   InvokeRuntimeCallingConvention calling_convention;
   1903   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   1904   Location outLocation = calling_convention.GetReturnLocation(DataType::Type::kInt32);
   1905   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
   1906 }
   1907 
   1908 void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
   1909   Mips64Assembler* assembler = GetAssembler();
   1910   LocationSummary* locations = invoke->GetLocations();
   1911 
   1912   GpuRegister string_to_copy = locations->InAt(0).AsRegister<GpuRegister>();
   1913   SlowPathCodeMIPS64* slow_path =
   1914       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS64(invoke);
   1915   codegen_->AddSlowPath(slow_path);
   1916   __ Beqzc(string_to_copy, slow_path->GetEntryLabel());
   1917 
   1918   codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc(), slow_path);
   1919   CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
   1920   __ Bind(slow_path->GetExitLabel());
   1921 }
   1922 
   1923 static void GenIsInfinite(LocationSummary* locations,
   1924                           bool is64bit,
   1925                           Mips64Assembler* assembler) {
   1926   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
   1927   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
   1928 
   1929   if (is64bit) {
   1930     __ ClassD(FTMP, in);
   1931   } else {
   1932     __ ClassS(FTMP, in);
   1933   }
   1934   __ Mfc1(out, FTMP);
   1935   __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
   1936   __ Sltu(out, ZERO, out);
   1937 }
   1938 
   1939 // boolean java.lang.Float.isInfinite(float)
   1940 void IntrinsicLocationsBuilderMIPS64::VisitFloatIsInfinite(HInvoke* invoke) {
   1941   CreateFPToIntLocations(allocator_, invoke);
   1942 }
   1943 
   1944 void IntrinsicCodeGeneratorMIPS64::VisitFloatIsInfinite(HInvoke* invoke) {
   1945   GenIsInfinite(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
   1946 }
   1947 
   1948 // boolean java.lang.Double.isInfinite(double)
   1949 void IntrinsicLocationsBuilderMIPS64::VisitDoubleIsInfinite(HInvoke* invoke) {
   1950   CreateFPToIntLocations(allocator_, invoke);
   1951 }
   1952 
   1953 void IntrinsicCodeGeneratorMIPS64::VisitDoubleIsInfinite(HInvoke* invoke) {
   1954   GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
   1955 }
   1956 
   1957 // void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
   1958 void IntrinsicLocationsBuilderMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
   1959   LocationSummary* locations =
   1960       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   1961   locations->SetInAt(0, Location::RequiresRegister());
   1962   locations->SetInAt(1, Location::RequiresRegister());
   1963   locations->SetInAt(2, Location::RequiresRegister());
   1964   locations->SetInAt(3, Location::RequiresRegister());
   1965   locations->SetInAt(4, Location::RequiresRegister());
   1966 
   1967   locations->AddTemp(Location::RequiresRegister());
   1968   locations->AddTemp(Location::RequiresRegister());
   1969   locations->AddTemp(Location::RequiresRegister());
   1970 }
   1971 
   1972 void IntrinsicCodeGeneratorMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
   1973   Mips64Assembler* assembler = GetAssembler();
   1974   LocationSummary* locations = invoke->GetLocations();
   1975 
   1976   // Check assumption that sizeof(Char) is 2 (used in scaling below).
   1977   const size_t char_size = DataType::Size(DataType::Type::kUint16);
   1978   DCHECK_EQ(char_size, 2u);
   1979   const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
   1980 
   1981   GpuRegister srcObj = locations->InAt(0).AsRegister<GpuRegister>();
   1982   GpuRegister srcBegin = locations->InAt(1).AsRegister<GpuRegister>();
   1983   GpuRegister srcEnd = locations->InAt(2).AsRegister<GpuRegister>();
   1984   GpuRegister dstObj = locations->InAt(3).AsRegister<GpuRegister>();
   1985   GpuRegister dstBegin = locations->InAt(4).AsRegister<GpuRegister>();
   1986 
   1987   GpuRegister dstPtr = locations->GetTemp(0).AsRegister<GpuRegister>();
   1988   GpuRegister srcPtr = locations->GetTemp(1).AsRegister<GpuRegister>();
   1989   GpuRegister numChrs = locations->GetTemp(2).AsRegister<GpuRegister>();
   1990 
   1991   Mips64Label done;
   1992   Mips64Label loop;
   1993 
   1994   // Location of data in char array buffer.
   1995   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
   1996 
   1997   // Get offset of value field within a string object.
   1998   const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
   1999 
   2000   __ Beqc(srcEnd, srcBegin, &done);  // No characters to move.
   2001 
   2002   // Calculate number of characters to be copied.
   2003   __ Dsubu(numChrs, srcEnd, srcBegin);
   2004 
   2005   // Calculate destination address.
   2006   __ Daddiu(dstPtr, dstObj, data_offset);
   2007   __ Dlsa(dstPtr, dstBegin, dstPtr, char_shift);
   2008 
   2009   if (mirror::kUseStringCompression) {
   2010     Mips64Label uncompressed_copy, compressed_loop;
   2011     const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
   2012     // Load count field and extract compression flag.
   2013     __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset);
   2014     __ Dext(TMP, TMP, 0, 1);
   2015 
   2016     // If string is uncompressed, use uncompressed path.
   2017     __ Bnezc(TMP, &uncompressed_copy);
   2018 
   2019     // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
   2020     __ Daddu(srcPtr, srcObj, srcBegin);
   2021     __ Bind(&compressed_loop);
   2022     __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset);
   2023     __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0);
   2024     __ Daddiu(numChrs, numChrs, -1);
   2025     __ Daddiu(srcPtr, srcPtr, 1);
   2026     __ Daddiu(dstPtr, dstPtr, 2);
   2027     __ Bnezc(numChrs, &compressed_loop);
   2028 
   2029     __ Bc(&done);
   2030     __ Bind(&uncompressed_copy);
   2031   }
   2032 
   2033   // Calculate source address.
   2034   __ Daddiu(srcPtr, srcObj, value_offset);
   2035   __ Dlsa(srcPtr, srcBegin, srcPtr, char_shift);
   2036 
   2037   __ Bind(&loop);
   2038   __ Lh(AT, srcPtr, 0);
   2039   __ Daddiu(numChrs, numChrs, -1);
   2040   __ Daddiu(srcPtr, srcPtr, char_size);
   2041   __ Sh(AT, dstPtr, 0);
   2042   __ Daddiu(dstPtr, dstPtr, char_size);
   2043   __ Bnezc(numChrs, &loop);
   2044 
   2045   __ Bind(&done);
   2046 }
   2047 
   2048 // static void java.lang.System.arraycopy(Object src, int srcPos,
   2049 //                                        Object dest, int destPos,
   2050 //                                        int length)
   2051 void IntrinsicLocationsBuilderMIPS64::VisitSystemArrayCopyChar(HInvoke* invoke) {
   2052   HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
   2053   HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
   2054   HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
   2055 
   2056   // As long as we are checking, we might as well check to see if the src and dest
   2057   // positions are >= 0.
   2058   if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
   2059       (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
   2060     // We will have to fail anyways.
   2061     return;
   2062   }
   2063 
   2064   // And since we are already checking, check the length too.
   2065   if (length != nullptr) {
   2066     int32_t len = length->GetValue();
   2067     if (len < 0) {
   2068       // Just call as normal.
   2069       return;
   2070     }
   2071   }
   2072 
   2073   // Okay, it is safe to generate inline code.
   2074   LocationSummary* locations =
   2075       new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
   2076   // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
   2077   locations->SetInAt(0, Location::RequiresRegister());
   2078   locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
   2079   locations->SetInAt(2, Location::RequiresRegister());
   2080   locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
   2081   locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
   2082 
   2083   locations->AddTemp(Location::RequiresRegister());
   2084   locations->AddTemp(Location::RequiresRegister());
   2085   locations->AddTemp(Location::RequiresRegister());
   2086 }
   2087 
   2088 // Utility routine to verify that "length(input) - pos >= length"
   2089 static void EnoughItems(Mips64Assembler* assembler,
   2090                         GpuRegister length_input_minus_pos,
   2091                         Location length,
   2092                         SlowPathCodeMIPS64* slow_path) {
   2093   if (length.IsConstant()) {
   2094     int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
   2095 
   2096     if (IsInt<16>(length_constant)) {
   2097       __ Slti(TMP, length_input_minus_pos, length_constant);
   2098       __ Bnezc(TMP, slow_path->GetEntryLabel());
   2099     } else {
   2100       __ LoadConst32(TMP, length_constant);
   2101       __ Bltc(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
   2102     }
   2103   } else {
   2104     __ Bltc(length_input_minus_pos, length.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
   2105   }
   2106 }
   2107 
   2108 static void CheckPosition(Mips64Assembler* assembler,
   2109                           Location pos,
   2110                           GpuRegister input,
   2111                           Location length,
   2112                           SlowPathCodeMIPS64* slow_path,
   2113                           bool length_is_input_length = false) {
   2114   // Where is the length in the Array?
   2115   const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
   2116 
   2117   // Calculate length(input) - pos.
   2118   if (pos.IsConstant()) {
   2119     int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
   2120     if (pos_const == 0) {
   2121       if (!length_is_input_length) {
   2122         // Check that length(input) >= length.
   2123         __ LoadFromOffset(kLoadWord, AT, input, length_offset);
   2124         EnoughItems(assembler, AT, length, slow_path);
   2125       }
   2126     } else {
   2127       // Check that (length(input) - pos) >= zero.
   2128       __ LoadFromOffset(kLoadWord, AT, input, length_offset);
   2129       DCHECK_GT(pos_const, 0);
   2130       __ Addiu32(AT, AT, -pos_const);
   2131       __ Bltzc(AT, slow_path->GetEntryLabel());
   2132 
   2133       // Verify that (length(input) - pos) >= length.
   2134       EnoughItems(assembler, AT, length, slow_path);
   2135     }
   2136   } else if (length_is_input_length) {
   2137     // The only way the copy can succeed is if pos is zero.
   2138     GpuRegister pos_reg = pos.AsRegister<GpuRegister>();
   2139     __ Bnezc(pos_reg, slow_path->GetEntryLabel());
   2140   } else {
   2141     // Verify that pos >= 0.
   2142     GpuRegister pos_reg = pos.AsRegister<GpuRegister>();
   2143     __ Bltzc(pos_reg, slow_path->GetEntryLabel());
   2144 
   2145     // Check that (length(input) - pos) >= zero.
   2146     __ LoadFromOffset(kLoadWord, AT, input, length_offset);
   2147     __ Subu(AT, AT, pos_reg);
   2148     __ Bltzc(AT, slow_path->GetEntryLabel());
   2149 
   2150     // Verify that (length(input) - pos) >= length.
   2151     EnoughItems(assembler, AT, length, slow_path);
   2152   }
   2153 }
   2154 
   2155 void IntrinsicCodeGeneratorMIPS64::VisitSystemArrayCopyChar(HInvoke* invoke) {
   2156   Mips64Assembler* assembler = GetAssembler();
   2157   LocationSummary* locations = invoke->GetLocations();
   2158 
   2159   GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
   2160   Location src_pos = locations->InAt(1);
   2161   GpuRegister dest = locations->InAt(2).AsRegister<GpuRegister>();
   2162   Location dest_pos = locations->InAt(3);
   2163   Location length = locations->InAt(4);
   2164 
   2165   Mips64Label loop;
   2166 
   2167   GpuRegister dest_base = locations->GetTemp(0).AsRegister<GpuRegister>();
   2168   GpuRegister src_base = locations->GetTemp(1).AsRegister<GpuRegister>();
   2169   GpuRegister count = locations->GetTemp(2).AsRegister<GpuRegister>();
   2170 
   2171   SlowPathCodeMIPS64* slow_path =
   2172       new (codegen_->GetScopedAllocator()) IntrinsicSlowPathMIPS64(invoke);
   2173   codegen_->AddSlowPath(slow_path);
   2174 
   2175   // Bail out if the source and destination are the same (to handle overlap).
   2176   __ Beqc(src, dest, slow_path->GetEntryLabel());
   2177 
   2178   // Bail out if the source is null.
   2179   __ Beqzc(src, slow_path->GetEntryLabel());
   2180 
   2181   // Bail out if the destination is null.
   2182   __ Beqzc(dest, slow_path->GetEntryLabel());
   2183 
   2184   // Load length into register for count.
   2185   if (length.IsConstant()) {
   2186     __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
   2187   } else {
   2188     // If the length is negative, bail out.
   2189     // We have already checked in the LocationsBuilder for the constant case.
   2190     __ Bltzc(length.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
   2191 
   2192     __ Move(count, length.AsRegister<GpuRegister>());
   2193   }
   2194 
   2195   // Validity checks: source.
   2196   CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
   2197 
   2198   // Validity checks: dest.
   2199   CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
   2200 
   2201   // If count is zero, we're done.
   2202   __ Beqzc(count, slow_path->GetExitLabel());
   2203 
   2204   // Okay, everything checks out.  Finally time to do the copy.
   2205   // Check assumption that sizeof(Char) is 2 (used in scaling below).
   2206   const size_t char_size = DataType::Size(DataType::Type::kUint16);
   2207   DCHECK_EQ(char_size, 2u);
   2208 
   2209   const size_t char_shift = DataType::SizeShift(DataType::Type::kUint16);
   2210 
   2211   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
   2212 
   2213   // Calculate source and destination addresses.
   2214   if (src_pos.IsConstant()) {
   2215     int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
   2216 
   2217     __ Daddiu64(src_base, src, data_offset + char_size * src_pos_const, TMP);
   2218   } else {
   2219     __ Daddiu64(src_base, src, data_offset, TMP);
   2220     __ Dlsa(src_base, src_pos.AsRegister<GpuRegister>(), src_base, char_shift);
   2221   }
   2222   if (dest_pos.IsConstant()) {
   2223     int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
   2224 
   2225     __ Daddiu64(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
   2226   } else {
   2227     __ Daddiu64(dest_base, dest, data_offset, TMP);
   2228     __ Dlsa(dest_base, dest_pos.AsRegister<GpuRegister>(), dest_base, char_shift);
   2229   }
   2230 
   2231   __ Bind(&loop);
   2232   __ Lh(TMP, src_base, 0);
   2233   __ Daddiu(src_base, src_base, char_size);
   2234   __ Daddiu(count, count, -1);
   2235   __ Sh(TMP, dest_base, 0);
   2236   __ Daddiu(dest_base, dest_base, char_size);
   2237   __ Bnezc(count, &loop);
   2238 
   2239   __ Bind(slow_path->GetExitLabel());
   2240 }
   2241 
   2242 static void GenHighestOneBit(LocationSummary* locations,
   2243                              DataType::Type type,
   2244                              Mips64Assembler* assembler) {
   2245   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64) << type;
   2246 
   2247   GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
   2248   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
   2249 
   2250   if (type == DataType::Type::kInt64) {
   2251     __ Dclz(TMP, in);
   2252     __ LoadConst64(AT, INT64_C(0x8000000000000000));
   2253     __ Dsrlv(AT, AT, TMP);
   2254   } else {
   2255     __ Clz(TMP, in);
   2256     __ LoadConst32(AT, 0x80000000);
   2257     __ Srlv(AT, AT, TMP);
   2258   }
   2259   // For either value of "type", when "in" is zero, "out" should also
   2260   // be zero. Without this extra "and" operation, when "in" is zero,
   2261   // "out" would be either Integer.MIN_VALUE, or Long.MIN_VALUE because
   2262   // the MIPS logical shift operations "dsrlv", and "srlv" don't use
   2263   // the shift amount (TMP) directly; they use either (TMP % 64) or
   2264   // (TMP % 32), respectively.
   2265   __ And(out, AT, in);
   2266 }
   2267 
   2268 // int java.lang.Integer.highestOneBit(int)
   2269 void IntrinsicLocationsBuilderMIPS64::VisitIntegerHighestOneBit(HInvoke* invoke) {
   2270   CreateIntToIntLocations(allocator_, invoke);
   2271 }
   2272 
   2273 void IntrinsicCodeGeneratorMIPS64::VisitIntegerHighestOneBit(HInvoke* invoke) {
   2274   GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
   2275 }
   2276 
   2277 // long java.lang.Long.highestOneBit(long)
   2278 void IntrinsicLocationsBuilderMIPS64::VisitLongHighestOneBit(HInvoke* invoke) {
   2279   CreateIntToIntLocations(allocator_, invoke);
   2280 }
   2281 
   2282 void IntrinsicCodeGeneratorMIPS64::VisitLongHighestOneBit(HInvoke* invoke) {
   2283   GenHighestOneBit(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
   2284 }
   2285 
   2286 static void GenLowestOneBit(LocationSummary* locations,
   2287                             DataType::Type type,
   2288                             Mips64Assembler* assembler) {
   2289   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64) << type;
   2290 
   2291   GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
   2292   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
   2293 
   2294   if (type == DataType::Type::kInt64) {
   2295     __ Dsubu(TMP, ZERO, in);
   2296   } else {
   2297     __ Subu(TMP, ZERO, in);
   2298   }
   2299   __ And(out, TMP, in);
   2300 }
   2301 
   2302 // int java.lang.Integer.lowestOneBit(int)
   2303 void IntrinsicLocationsBuilderMIPS64::VisitIntegerLowestOneBit(HInvoke* invoke) {
   2304   CreateIntToIntLocations(allocator_, invoke);
   2305 }
   2306 
   2307 void IntrinsicCodeGeneratorMIPS64::VisitIntegerLowestOneBit(HInvoke* invoke) {
   2308   GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler());
   2309 }
   2310 
   2311 // long java.lang.Long.lowestOneBit(long)
   2312 void IntrinsicLocationsBuilderMIPS64::VisitLongLowestOneBit(HInvoke* invoke) {
   2313   CreateIntToIntLocations(allocator_, invoke);
   2314 }
   2315 
   2316 void IntrinsicCodeGeneratorMIPS64::VisitLongLowestOneBit(HInvoke* invoke) {
   2317   GenLowestOneBit(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler());
   2318 }
   2319 
   2320 static void CreateFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
   2321   LocationSummary* locations =
   2322       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
   2323   InvokeRuntimeCallingConvention calling_convention;
   2324 
   2325   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   2326   locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
   2327 }
   2328 
   2329 static void CreateFPFPToFPCallLocations(ArenaAllocator* allocator, HInvoke* invoke) {
   2330   LocationSummary* locations =
   2331       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified);
   2332   InvokeRuntimeCallingConvention calling_convention;
   2333 
   2334   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   2335   locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
   2336   locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kFloat64));
   2337 }
   2338 
   2339 static void GenFPToFPCall(HInvoke* invoke,
   2340                           CodeGeneratorMIPS64* codegen,
   2341                           QuickEntrypointEnum entry) {
   2342   LocationSummary* locations = invoke->GetLocations();
   2343   FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
   2344   DCHECK_EQ(in, F12);
   2345   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
   2346   DCHECK_EQ(out, F0);
   2347 
   2348   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
   2349 }
   2350 
   2351 static void GenFPFPToFPCall(HInvoke* invoke,
   2352                             CodeGeneratorMIPS64* codegen,
   2353                             QuickEntrypointEnum entry) {
   2354   LocationSummary* locations = invoke->GetLocations();
   2355   FpuRegister in0 = locations->InAt(0).AsFpuRegister<FpuRegister>();
   2356   DCHECK_EQ(in0, F12);
   2357   FpuRegister in1 = locations->InAt(1).AsFpuRegister<FpuRegister>();
   2358   DCHECK_EQ(in1, F13);
   2359   FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
   2360   DCHECK_EQ(out, F0);
   2361 
   2362   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
   2363 }
   2364 
   2365 // static double java.lang.Math.cos(double a)
   2366 void IntrinsicLocationsBuilderMIPS64::VisitMathCos(HInvoke* invoke) {
   2367   CreateFPToFPCallLocations(allocator_, invoke);
   2368 }
   2369 
   2370 void IntrinsicCodeGeneratorMIPS64::VisitMathCos(HInvoke* invoke) {
   2371   GenFPToFPCall(invoke, codegen_, kQuickCos);
   2372 }
   2373 
   2374 // static double java.lang.Math.sin(double a)
   2375 void IntrinsicLocationsBuilderMIPS64::VisitMathSin(HInvoke* invoke) {
   2376   CreateFPToFPCallLocations(allocator_, invoke);
   2377 }
   2378 
   2379 void IntrinsicCodeGeneratorMIPS64::VisitMathSin(HInvoke* invoke) {
   2380   GenFPToFPCall(invoke, codegen_, kQuickSin);
   2381 }
   2382 
   2383 // static double java.lang.Math.acos(double a)
   2384 void IntrinsicLocationsBuilderMIPS64::VisitMathAcos(HInvoke* invoke) {
   2385   CreateFPToFPCallLocations(allocator_, invoke);
   2386 }
   2387 
   2388 void IntrinsicCodeGeneratorMIPS64::VisitMathAcos(HInvoke* invoke) {
   2389   GenFPToFPCall(invoke, codegen_, kQuickAcos);
   2390 }
   2391 
   2392 // static double java.lang.Math.asin(double a)
   2393 void IntrinsicLocationsBuilderMIPS64::VisitMathAsin(HInvoke* invoke) {
   2394   CreateFPToFPCallLocations(allocator_, invoke);
   2395 }
   2396 
   2397 void IntrinsicCodeGeneratorMIPS64::VisitMathAsin(HInvoke* invoke) {
   2398   GenFPToFPCall(invoke, codegen_, kQuickAsin);
   2399 }
   2400 
   2401 // static double java.lang.Math.atan(double a)
   2402 void IntrinsicLocationsBuilderMIPS64::VisitMathAtan(HInvoke* invoke) {
   2403   CreateFPToFPCallLocations(allocator_, invoke);
   2404 }
   2405 
   2406 void IntrinsicCodeGeneratorMIPS64::VisitMathAtan(HInvoke* invoke) {
   2407   GenFPToFPCall(invoke, codegen_, kQuickAtan);
   2408 }
   2409 
   2410 // static double java.lang.Math.atan2(double y, double x)
   2411 void IntrinsicLocationsBuilderMIPS64::VisitMathAtan2(HInvoke* invoke) {
   2412   CreateFPFPToFPCallLocations(allocator_, invoke);
   2413 }
   2414 
   2415 void IntrinsicCodeGeneratorMIPS64::VisitMathAtan2(HInvoke* invoke) {
   2416   GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
   2417 }
   2418 
   2419 // static double java.lang.Math.pow(double y, double x)
   2420 void IntrinsicLocationsBuilderMIPS64::VisitMathPow(HInvoke* invoke) {
   2421   CreateFPFPToFPCallLocations(allocator_, invoke);
   2422 }
   2423 
   2424 void IntrinsicCodeGeneratorMIPS64::VisitMathPow(HInvoke* invoke) {
   2425   GenFPFPToFPCall(invoke, codegen_, kQuickPow);
   2426 }
   2427 
   2428 // static double java.lang.Math.cbrt(double a)
   2429 void IntrinsicLocationsBuilderMIPS64::VisitMathCbrt(HInvoke* invoke) {
   2430   CreateFPToFPCallLocations(allocator_, invoke);
   2431 }
   2432 
   2433 void IntrinsicCodeGeneratorMIPS64::VisitMathCbrt(HInvoke* invoke) {
   2434   GenFPToFPCall(invoke, codegen_, kQuickCbrt);
   2435 }
   2436 
   2437 // static double java.lang.Math.cosh(double x)
   2438 void IntrinsicLocationsBuilderMIPS64::VisitMathCosh(HInvoke* invoke) {
   2439   CreateFPToFPCallLocations(allocator_, invoke);
   2440 }
   2441 
   2442 void IntrinsicCodeGeneratorMIPS64::VisitMathCosh(HInvoke* invoke) {
   2443   GenFPToFPCall(invoke, codegen_, kQuickCosh);
   2444 }
   2445 
   2446 // static double java.lang.Math.exp(double a)
   2447 void IntrinsicLocationsBuilderMIPS64::VisitMathExp(HInvoke* invoke) {
   2448   CreateFPToFPCallLocations(allocator_, invoke);
   2449 }
   2450 
   2451 void IntrinsicCodeGeneratorMIPS64::VisitMathExp(HInvoke* invoke) {
   2452   GenFPToFPCall(invoke, codegen_, kQuickExp);
   2453 }
   2454 
   2455 // static double java.lang.Math.expm1(double x)
   2456 void IntrinsicLocationsBuilderMIPS64::VisitMathExpm1(HInvoke* invoke) {
   2457   CreateFPToFPCallLocations(allocator_, invoke);
   2458 }
   2459 
   2460 void IntrinsicCodeGeneratorMIPS64::VisitMathExpm1(HInvoke* invoke) {
   2461   GenFPToFPCall(invoke, codegen_, kQuickExpm1);
   2462 }
   2463 
   2464 // static double java.lang.Math.hypot(double x, double y)
   2465 void IntrinsicLocationsBuilderMIPS64::VisitMathHypot(HInvoke* invoke) {
   2466   CreateFPFPToFPCallLocations(allocator_, invoke);
   2467 }
   2468 
   2469 void IntrinsicCodeGeneratorMIPS64::VisitMathHypot(HInvoke* invoke) {
   2470   GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
   2471 }
   2472 
   2473 // static double java.lang.Math.log(double a)
   2474 void IntrinsicLocationsBuilderMIPS64::VisitMathLog(HInvoke* invoke) {
   2475   CreateFPToFPCallLocations(allocator_, invoke);
   2476 }
   2477 
   2478 void IntrinsicCodeGeneratorMIPS64::VisitMathLog(HInvoke* invoke) {
   2479   GenFPToFPCall(invoke, codegen_, kQuickLog);
   2480 }
   2481 
   2482 // static double java.lang.Math.log10(double x)
   2483 void IntrinsicLocationsBuilderMIPS64::VisitMathLog10(HInvoke* invoke) {
   2484   CreateFPToFPCallLocations(allocator_, invoke);
   2485 }
   2486 
   2487 void IntrinsicCodeGeneratorMIPS64::VisitMathLog10(HInvoke* invoke) {
   2488   GenFPToFPCall(invoke, codegen_, kQuickLog10);
   2489 }
   2490 
   2491 // static double java.lang.Math.nextAfter(double start, double direction)
   2492 void IntrinsicLocationsBuilderMIPS64::VisitMathNextAfter(HInvoke* invoke) {
   2493   CreateFPFPToFPCallLocations(allocator_, invoke);
   2494 }
   2495 
   2496 void IntrinsicCodeGeneratorMIPS64::VisitMathNextAfter(HInvoke* invoke) {
   2497   GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
   2498 }
   2499 
   2500 // static double java.lang.Math.sinh(double x)
   2501 void IntrinsicLocationsBuilderMIPS64::VisitMathSinh(HInvoke* invoke) {
   2502   CreateFPToFPCallLocations(allocator_, invoke);
   2503 }
   2504 
   2505 void IntrinsicCodeGeneratorMIPS64::VisitMathSinh(HInvoke* invoke) {
   2506   GenFPToFPCall(invoke, codegen_, kQuickSinh);
   2507 }
   2508 
   2509 // static double java.lang.Math.tan(double a)
   2510 void IntrinsicLocationsBuilderMIPS64::VisitMathTan(HInvoke* invoke) {
   2511   CreateFPToFPCallLocations(allocator_, invoke);
   2512 }
   2513 
   2514 void IntrinsicCodeGeneratorMIPS64::VisitMathTan(HInvoke* invoke) {
   2515   GenFPToFPCall(invoke, codegen_, kQuickTan);
   2516 }
   2517 
   2518 // static double java.lang.Math.tanh(double x)
   2519 void IntrinsicLocationsBuilderMIPS64::VisitMathTanh(HInvoke* invoke) {
   2520   CreateFPToFPCallLocations(allocator_, invoke);
   2521 }
   2522 
   2523 void IntrinsicCodeGeneratorMIPS64::VisitMathTanh(HInvoke* invoke) {
   2524   GenFPToFPCall(invoke, codegen_, kQuickTanh);
   2525 }
   2526 
   2527 // long java.lang.Integer.valueOf(long)
   2528 void IntrinsicLocationsBuilderMIPS64::VisitIntegerValueOf(HInvoke* invoke) {
   2529   InvokeRuntimeCallingConvention calling_convention;
   2530   IntrinsicVisitor::ComputeIntegerValueOfLocations(
   2531       invoke,
   2532       codegen_,
   2533       calling_convention.GetReturnLocation(DataType::Type::kReference),
   2534       Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2535 }
   2536 
   2537 void IntrinsicCodeGeneratorMIPS64::VisitIntegerValueOf(HInvoke* invoke) {
   2538   IntrinsicVisitor::IntegerValueOfInfo info = IntrinsicVisitor::ComputeIntegerValueOfInfo();
   2539   LocationSummary* locations = invoke->GetLocations();
   2540   Mips64Assembler* assembler = GetAssembler();
   2541   InstructionCodeGeneratorMIPS64* icodegen =
   2542       down_cast<InstructionCodeGeneratorMIPS64*>(codegen_->GetInstructionVisitor());
   2543 
   2544   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
   2545   InvokeRuntimeCallingConvention calling_convention;
   2546   if (invoke->InputAt(0)->IsConstant()) {
   2547     int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
   2548     if (value >= info.low && value <= info.high) {
   2549       // Just embed the j.l.Integer in the code.
   2550       ScopedObjectAccess soa(Thread::Current());
   2551       mirror::Object* boxed = info.cache->Get(value + (-info.low));
   2552       DCHECK(boxed != nullptr && Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boxed));
   2553       uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(boxed));
   2554       __ LoadConst64(out, address);
   2555     } else {
   2556       // Allocate and initialize a new j.l.Integer.
   2557       // TODO: If we JIT, we could allocate the j.l.Integer now, and store it in the
   2558       // JIT object table.
   2559       uint32_t address =
   2560           dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
   2561       __ LoadConst64(calling_convention.GetRegisterAt(0), address);
   2562       codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
   2563       CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
   2564       __ StoreConstToOffset(kStoreWord, value, out, info.value_offset, TMP);
   2565       // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
   2566       // one.
   2567       icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
   2568     }
   2569   } else {
   2570     GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
   2571     Mips64Label allocate, done;
   2572     int32_t count = static_cast<uint32_t>(info.high) - info.low + 1;
   2573 
   2574     // Is (info.low <= in) && (in <= info.high)?
   2575     __ Addiu32(out, in, -info.low);
   2576     // As unsigned quantities is out < (info.high - info.low + 1)?
   2577     __ LoadConst32(AT, count);
   2578     // Branch if out >= (info.high - info.low + 1).
   2579     // This means that "in" is outside of the range [info.low, info.high].
   2580     __ Bgeuc(out, AT, &allocate);
   2581 
   2582     // If the value is within the bounds, load the j.l.Integer directly from the array.
   2583     uint32_t data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
   2584     uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.cache));
   2585     __ LoadConst64(TMP, data_offset + address);
   2586     __ Dlsa(out, out, TMP, TIMES_4);
   2587     __ Lwu(out, out, 0);
   2588     __ MaybeUnpoisonHeapReference(out);
   2589     __ Bc(&done);
   2590 
   2591     __ Bind(&allocate);
   2592     // Otherwise allocate and initialize a new j.l.Integer.
   2593     address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
   2594     __ LoadConst64(calling_convention.GetRegisterAt(0), address);
   2595     codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
   2596     CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
   2597     __ StoreToOffset(kStoreWord, in, out, info.value_offset);
   2598     // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
   2599     // one.
   2600     icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
   2601     __ Bind(&done);
   2602   }
   2603 }
   2604 
   2605 // static boolean java.lang.Thread.interrupted()
   2606 void IntrinsicLocationsBuilderMIPS64::VisitThreadInterrupted(HInvoke* invoke) {
   2607   LocationSummary* locations =
   2608       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   2609   locations->SetOut(Location::RequiresRegister());
   2610 }
   2611 
   2612 void IntrinsicCodeGeneratorMIPS64::VisitThreadInterrupted(HInvoke* invoke) {
   2613   Mips64Assembler* assembler = GetAssembler();
   2614   GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
   2615   int32_t offset = Thread::InterruptedOffset<kMips64PointerSize>().Int32Value();
   2616   __ LoadFromOffset(kLoadWord, out, TR, offset);
   2617   Mips64Label done;
   2618   __ Beqzc(out, &done);
   2619   __ Sync(0);
   2620   __ StoreToOffset(kStoreWord, ZERO, TR, offset);
   2621   __ Sync(0);
   2622   __ Bind(&done);
   2623 }
   2624 
   2625 void IntrinsicLocationsBuilderMIPS64::VisitReachabilityFence(HInvoke* invoke) {
   2626   LocationSummary* locations =
   2627       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   2628   locations->SetInAt(0, Location::Any());
   2629 }
   2630 
   2631 void IntrinsicCodeGeneratorMIPS64::VisitReachabilityFence(HInvoke* invoke ATTRIBUTE_UNUSED) { }
   2632 
   2633 UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
   2634 UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
   2635 
   2636 UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf);
   2637 UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter);
   2638 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferAppend);
   2639 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferLength);
   2640 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferToString);
   2641 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderAppend);
   2642 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderLength);
   2643 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderToString);
   2644 
   2645 // 1.8.
   2646 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddInt)
   2647 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddLong)
   2648 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetInt)
   2649 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetLong)
   2650 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetObject)
   2651 
   2652 UNREACHABLE_INTRINSICS(MIPS64)
   2653 
   2654 #undef __
   2655 
   2656 }  // namespace mips64
   2657 }  // namespace art
   2658