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_mips.h"
     18 
     19 #include "arch/mips/instruction_set_features_mips.h"
     20 #include "art_method.h"
     21 #include "code_generator_mips.h"
     22 #include "entrypoints/quick/quick_entrypoints.h"
     23 #include "intrinsics.h"
     24 #include "mirror/array-inl.h"
     25 #include "mirror/string.h"
     26 #include "thread.h"
     27 #include "utils/mips/assembler_mips.h"
     28 #include "utils/mips/constants_mips.h"
     29 
     30 namespace art {
     31 
     32 namespace mips {
     33 
     34 IntrinsicLocationsBuilderMIPS::IntrinsicLocationsBuilderMIPS(CodeGeneratorMIPS* codegen)
     35   : arena_(codegen->GetGraph()->GetArena()) {
     36 }
     37 
     38 MipsAssembler* IntrinsicCodeGeneratorMIPS::GetAssembler() {
     39   return reinterpret_cast<MipsAssembler*>(codegen_->GetAssembler());
     40 }
     41 
     42 ArenaAllocator* IntrinsicCodeGeneratorMIPS::GetAllocator() {
     43   return codegen_->GetGraph()->GetArena();
     44 }
     45 
     46 inline bool IntrinsicCodeGeneratorMIPS::IsR2OrNewer() const {
     47   return codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
     48 }
     49 
     50 inline bool IntrinsicCodeGeneratorMIPS::IsR6() const {
     51   return codegen_->GetInstructionSetFeatures().IsR6();
     52 }
     53 
     54 inline bool IntrinsicCodeGeneratorMIPS::Is32BitFPU() const {
     55   return codegen_->GetInstructionSetFeatures().Is32BitFloatingPoint();
     56 }
     57 
     58 #define __ codegen->GetAssembler()->
     59 
     60 static void MoveFromReturnRegister(Location trg,
     61                                    Primitive::Type type,
     62                                    CodeGeneratorMIPS* codegen) {
     63   if (!trg.IsValid()) {
     64     DCHECK_EQ(type, Primitive::kPrimVoid);
     65     return;
     66   }
     67 
     68   DCHECK_NE(type, Primitive::kPrimVoid);
     69 
     70   if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
     71     Register trg_reg = trg.AsRegister<Register>();
     72     if (trg_reg != V0) {
     73       __ Move(V0, trg_reg);
     74     }
     75   } else {
     76     FRegister trg_reg = trg.AsFpuRegister<FRegister>();
     77     if (trg_reg != F0) {
     78       if (type == Primitive::kPrimFloat) {
     79         __ MovS(F0, trg_reg);
     80       } else {
     81         __ MovD(F0, trg_reg);
     82       }
     83     }
     84   }
     85 }
     86 
     87 static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
     88   InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
     89   IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
     90 }
     91 
     92 // Slow-path for fallback (calling the managed code to handle the
     93 // intrinsic) in an intrinsified call. This will copy the arguments
     94 // into the positions for a regular call.
     95 //
     96 // Note: The actual parameters are required to be in the locations
     97 //       given by the invoke's location summary. If an intrinsic
     98 //       modifies those locations before a slowpath call, they must be
     99 //       restored!
    100 class IntrinsicSlowPathMIPS : public SlowPathCodeMIPS {
    101  public:
    102   explicit IntrinsicSlowPathMIPS(HInvoke* invoke) : SlowPathCodeMIPS(invoke), invoke_(invoke) { }
    103 
    104   void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
    105     CodeGeneratorMIPS* codegen = down_cast<CodeGeneratorMIPS*>(codegen_in);
    106 
    107     __ Bind(GetEntryLabel());
    108 
    109     SaveLiveRegisters(codegen, invoke_->GetLocations());
    110 
    111     MoveArguments(invoke_, codegen);
    112 
    113     if (invoke_->IsInvokeStaticOrDirect()) {
    114       codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
    115                                           Location::RegisterLocation(A0));
    116     } else {
    117       codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0));
    118     }
    119     codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
    120 
    121     // Copy the result back to the expected output.
    122     Location out = invoke_->GetLocations()->Out();
    123     if (out.IsValid()) {
    124       DCHECK(out.IsRegister());  // TODO: Replace this when we support output in memory.
    125       DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
    126       MoveFromReturnRegister(out, invoke_->GetType(), codegen);
    127     }
    128 
    129     RestoreLiveRegisters(codegen, invoke_->GetLocations());
    130     __ B(GetExitLabel());
    131   }
    132 
    133   const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS"; }
    134 
    135  private:
    136   // The instruction where this slow path is happening.
    137   HInvoke* const invoke_;
    138 
    139   DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS);
    140 };
    141 
    142 #undef __
    143 
    144 bool IntrinsicLocationsBuilderMIPS::TryDispatch(HInvoke* invoke) {
    145   Dispatch(invoke);
    146   LocationSummary* res = invoke->GetLocations();
    147   return res != nullptr && res->Intrinsified();
    148 }
    149 
    150 #define __ assembler->
    151 
    152 static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
    153   LocationSummary* locations = new (arena) LocationSummary(invoke,
    154                                                            LocationSummary::kNoCall,
    155                                                            kIntrinsified);
    156   locations->SetInAt(0, Location::RequiresFpuRegister());
    157   locations->SetOut(Location::RequiresRegister());
    158 }
    159 
    160 static void MoveFPToInt(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
    161   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
    162 
    163   if (is64bit) {
    164     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
    165     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
    166 
    167     __ Mfc1(out_lo, in);
    168     __ MoveFromFpuHigh(out_hi, in);
    169   } else {
    170     Register out = locations->Out().AsRegister<Register>();
    171 
    172     __ Mfc1(out, in);
    173   }
    174 }
    175 
    176 // long java.lang.Double.doubleToRawLongBits(double)
    177 void IntrinsicLocationsBuilderMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
    178   CreateFPToIntLocations(arena_, invoke);
    179 }
    180 
    181 void IntrinsicCodeGeneratorMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
    182   MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    183 }
    184 
    185 // int java.lang.Float.floatToRawIntBits(float)
    186 void IntrinsicLocationsBuilderMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
    187   CreateFPToIntLocations(arena_, invoke);
    188 }
    189 
    190 void IntrinsicCodeGeneratorMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
    191   MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    192 }
    193 
    194 static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
    195   LocationSummary* locations = new (arena) LocationSummary(invoke,
    196                                                            LocationSummary::kNoCall,
    197                                                            kIntrinsified);
    198   locations->SetInAt(0, Location::RequiresRegister());
    199   locations->SetOut(Location::RequiresFpuRegister());
    200 }
    201 
    202 static void MoveIntToFP(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
    203   FRegister out = locations->Out().AsFpuRegister<FRegister>();
    204 
    205   if (is64bit) {
    206     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
    207     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
    208 
    209     __ Mtc1(in_lo, out);
    210     __ MoveToFpuHigh(in_hi, out);
    211   } else {
    212     Register in = locations->InAt(0).AsRegister<Register>();
    213 
    214     __ Mtc1(in, out);
    215   }
    216 }
    217 
    218 // double java.lang.Double.longBitsToDouble(long)
    219 void IntrinsicLocationsBuilderMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
    220   CreateIntToFPLocations(arena_, invoke);
    221 }
    222 
    223 void IntrinsicCodeGeneratorMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
    224   MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    225 }
    226 
    227 // float java.lang.Float.intBitsToFloat(int)
    228 void IntrinsicLocationsBuilderMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) {
    229   CreateIntToFPLocations(arena_, invoke);
    230 }
    231 
    232 void IntrinsicCodeGeneratorMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) {
    233   MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    234 }
    235 
    236 static void CreateIntToIntLocations(ArenaAllocator* arena,
    237                                     HInvoke* invoke,
    238                                     Location::OutputOverlap overlaps = Location::kNoOutputOverlap) {
    239   LocationSummary* locations = new (arena) LocationSummary(invoke,
    240                                                            LocationSummary::kNoCall,
    241                                                            kIntrinsified);
    242   locations->SetInAt(0, Location::RequiresRegister());
    243   locations->SetOut(Location::RequiresRegister(), overlaps);
    244 }
    245 
    246 static void GenReverse(LocationSummary* locations,
    247                        Primitive::Type type,
    248                        bool isR2OrNewer,
    249                        bool isR6,
    250                        bool reverseBits,
    251                        MipsAssembler* assembler) {
    252   DCHECK(type == Primitive::kPrimShort ||
    253          type == Primitive::kPrimInt ||
    254          type == Primitive::kPrimLong);
    255   DCHECK(type != Primitive::kPrimShort || !reverseBits);
    256 
    257   if (type == Primitive::kPrimShort) {
    258     Register in = locations->InAt(0).AsRegister<Register>();
    259     Register out = locations->Out().AsRegister<Register>();
    260 
    261     if (isR2OrNewer) {
    262       __ Wsbh(out, in);
    263       __ Seh(out, out);
    264     } else {
    265       __ Sll(TMP, in, 24);
    266       __ Sra(TMP, TMP, 16);
    267       __ Sll(out, in, 16);
    268       __ Srl(out, out, 24);
    269       __ Or(out, out, TMP);
    270     }
    271   } else if (type == Primitive::kPrimInt) {
    272     Register in = locations->InAt(0).AsRegister<Register>();
    273     Register out = locations->Out().AsRegister<Register>();
    274 
    275     if (isR2OrNewer) {
    276       __ Rotr(out, in, 16);
    277       __ Wsbh(out, out);
    278     } else {
    279       // MIPS32r1
    280       // __ Rotr(out, in, 16);
    281       __ Sll(TMP, in, 16);
    282       __ Srl(out, in, 16);
    283       __ Or(out, out, TMP);
    284       // __ Wsbh(out, out);
    285       __ LoadConst32(AT, 0x00FF00FF);
    286       __ And(TMP, out, AT);
    287       __ Sll(TMP, TMP, 8);
    288       __ Srl(out, out, 8);
    289       __ And(out, out, AT);
    290       __ Or(out, out, TMP);
    291     }
    292     if (reverseBits) {
    293       if (isR6) {
    294         __ Bitswap(out, out);
    295       } else {
    296         __ LoadConst32(AT, 0x0F0F0F0F);
    297         __ And(TMP, out, AT);
    298         __ Sll(TMP, TMP, 4);
    299         __ Srl(out, out, 4);
    300         __ And(out, out, AT);
    301         __ Or(out, TMP, out);
    302         __ LoadConst32(AT, 0x33333333);
    303         __ And(TMP, out, AT);
    304         __ Sll(TMP, TMP, 2);
    305         __ Srl(out, out, 2);
    306         __ And(out, out, AT);
    307         __ Or(out, TMP, out);
    308         __ LoadConst32(AT, 0x55555555);
    309         __ And(TMP, out, AT);
    310         __ Sll(TMP, TMP, 1);
    311         __ Srl(out, out, 1);
    312         __ And(out, out, AT);
    313         __ Or(out, TMP, out);
    314       }
    315     }
    316   } else if (type == Primitive::kPrimLong) {
    317     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
    318     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
    319     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
    320     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
    321 
    322     if (isR2OrNewer) {
    323       __ Rotr(AT, in_hi, 16);
    324       __ Rotr(TMP, in_lo, 16);
    325       __ Wsbh(out_lo, AT);
    326       __ Wsbh(out_hi, TMP);
    327     } else {
    328       // When calling CreateIntToIntLocations() we promised that the
    329       // use of the out_lo/out_hi wouldn't overlap with the use of
    330       // in_lo/in_hi. Be very careful not to write to out_lo/out_hi
    331       // until we're completely done reading from in_lo/in_hi.
    332       // __ Rotr(TMP, in_lo, 16);
    333       __ Sll(TMP, in_lo, 16);
    334       __ Srl(AT, in_lo, 16);
    335       __ Or(TMP, TMP, AT);             // Hold in TMP until it's safe
    336                                        // to write to out_hi.
    337       // __ Rotr(out_lo, in_hi, 16);
    338       __ Sll(AT, in_hi, 16);
    339       __ Srl(out_lo, in_hi, 16);        // Here we are finally done reading
    340                                         // from in_lo/in_hi so it's okay to
    341                                         // write to out_lo/out_hi.
    342       __ Or(out_lo, out_lo, AT);
    343       // __ Wsbh(out_hi, out_hi);
    344       __ LoadConst32(AT, 0x00FF00FF);
    345       __ And(out_hi, TMP, AT);
    346       __ Sll(out_hi, out_hi, 8);
    347       __ Srl(TMP, TMP, 8);
    348       __ And(TMP, TMP, AT);
    349       __ Or(out_hi, out_hi, TMP);
    350       // __ Wsbh(out_lo, out_lo);
    351       __ And(TMP, out_lo, AT);  // AT already holds the correct mask value
    352       __ Sll(TMP, TMP, 8);
    353       __ Srl(out_lo, out_lo, 8);
    354       __ And(out_lo, out_lo, AT);
    355       __ Or(out_lo, out_lo, TMP);
    356     }
    357     if (reverseBits) {
    358       if (isR6) {
    359         __ Bitswap(out_hi, out_hi);
    360         __ Bitswap(out_lo, out_lo);
    361       } else {
    362         __ LoadConst32(AT, 0x0F0F0F0F);
    363         __ And(TMP, out_hi, AT);
    364         __ Sll(TMP, TMP, 4);
    365         __ Srl(out_hi, out_hi, 4);
    366         __ And(out_hi, out_hi, AT);
    367         __ Or(out_hi, TMP, out_hi);
    368         __ And(TMP, out_lo, AT);
    369         __ Sll(TMP, TMP, 4);
    370         __ Srl(out_lo, out_lo, 4);
    371         __ And(out_lo, out_lo, AT);
    372         __ Or(out_lo, TMP, out_lo);
    373         __ LoadConst32(AT, 0x33333333);
    374         __ And(TMP, out_hi, AT);
    375         __ Sll(TMP, TMP, 2);
    376         __ Srl(out_hi, out_hi, 2);
    377         __ And(out_hi, out_hi, AT);
    378         __ Or(out_hi, TMP, out_hi);
    379         __ And(TMP, out_lo, AT);
    380         __ Sll(TMP, TMP, 2);
    381         __ Srl(out_lo, out_lo, 2);
    382         __ And(out_lo, out_lo, AT);
    383         __ Or(out_lo, TMP, out_lo);
    384         __ LoadConst32(AT, 0x55555555);
    385         __ And(TMP, out_hi, AT);
    386         __ Sll(TMP, TMP, 1);
    387         __ Srl(out_hi, out_hi, 1);
    388         __ And(out_hi, out_hi, AT);
    389         __ Or(out_hi, TMP, out_hi);
    390         __ And(TMP, out_lo, AT);
    391         __ Sll(TMP, TMP, 1);
    392         __ Srl(out_lo, out_lo, 1);
    393         __ And(out_lo, out_lo, AT);
    394         __ Or(out_lo, TMP, out_lo);
    395       }
    396     }
    397   }
    398 }
    399 
    400 // int java.lang.Integer.reverseBytes(int)
    401 void IntrinsicLocationsBuilderMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
    402   CreateIntToIntLocations(arena_, invoke);
    403 }
    404 
    405 void IntrinsicCodeGeneratorMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
    406   GenReverse(invoke->GetLocations(),
    407              Primitive::kPrimInt,
    408              IsR2OrNewer(),
    409              IsR6(),
    410              /* reverseBits */ false,
    411              GetAssembler());
    412 }
    413 
    414 // long java.lang.Long.reverseBytes(long)
    415 void IntrinsicLocationsBuilderMIPS::VisitLongReverseBytes(HInvoke* invoke) {
    416   CreateIntToIntLocations(arena_, invoke);
    417 }
    418 
    419 void IntrinsicCodeGeneratorMIPS::VisitLongReverseBytes(HInvoke* invoke) {
    420   GenReverse(invoke->GetLocations(),
    421              Primitive::kPrimLong,
    422              IsR2OrNewer(),
    423              IsR6(),
    424              /* reverseBits */ false,
    425              GetAssembler());
    426 }
    427 
    428 // short java.lang.Short.reverseBytes(short)
    429 void IntrinsicLocationsBuilderMIPS::VisitShortReverseBytes(HInvoke* invoke) {
    430   CreateIntToIntLocations(arena_, invoke);
    431 }
    432 
    433 void IntrinsicCodeGeneratorMIPS::VisitShortReverseBytes(HInvoke* invoke) {
    434   GenReverse(invoke->GetLocations(),
    435              Primitive::kPrimShort,
    436              IsR2OrNewer(),
    437              IsR6(),
    438              /* reverseBits */ false,
    439              GetAssembler());
    440 }
    441 
    442 static void GenNumberOfLeadingZeroes(LocationSummary* locations,
    443                                      bool is64bit,
    444                                      bool isR6,
    445                                      MipsAssembler* assembler) {
    446   Register out = locations->Out().AsRegister<Register>();
    447   if (is64bit) {
    448     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
    449     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
    450 
    451     if (isR6) {
    452       __ ClzR6(AT, in_hi);
    453       __ ClzR6(TMP, in_lo);
    454       __ Seleqz(TMP, TMP, in_hi);
    455     } else {
    456       __ ClzR2(AT, in_hi);
    457       __ ClzR2(TMP, in_lo);
    458       __ Movn(TMP, ZERO, in_hi);
    459     }
    460     __ Addu(out, AT, TMP);
    461   } else {
    462     Register in = locations->InAt(0).AsRegister<Register>();
    463 
    464     if (isR6) {
    465       __ ClzR6(out, in);
    466     } else {
    467       __ ClzR2(out, in);
    468     }
    469   }
    470 }
    471 
    472 // int java.lang.Integer.numberOfLeadingZeros(int i)
    473 void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
    474   CreateIntToIntLocations(arena_, invoke);
    475 }
    476 
    477 void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
    478   GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ false, IsR6(), GetAssembler());
    479 }
    480 
    481 // int java.lang.Long.numberOfLeadingZeros(long i)
    482 void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
    483   CreateIntToIntLocations(arena_, invoke);
    484 }
    485 
    486 void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
    487   GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ true, IsR6(), GetAssembler());
    488 }
    489 
    490 static void GenNumberOfTrailingZeroes(LocationSummary* locations,
    491                                       bool is64bit,
    492                                       bool isR6,
    493                                       MipsAssembler* assembler) {
    494   Register out = locations->Out().AsRegister<Register>();
    495   Register in_lo;
    496   Register in;
    497 
    498   if (is64bit) {
    499     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
    500 
    501     in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
    502 
    503     // If in_lo is zero then count the number of trailing zeroes in in_hi;
    504     // otherwise count the number of trailing zeroes in in_lo.
    505     // out = in_lo ? in_lo : in_hi;
    506     if (isR6) {
    507       __ Seleqz(out, in_hi, in_lo);
    508       __ Selnez(TMP, in_lo, in_lo);
    509       __ Or(out, out, TMP);
    510     } else {
    511       __ Movz(out, in_hi, in_lo);
    512       __ Movn(out, in_lo, in_lo);
    513     }
    514 
    515     in = out;
    516   } else {
    517     in = locations->InAt(0).AsRegister<Register>();
    518     // Give in_lo a dummy value to keep the compiler from complaining.
    519     // Since we only get here in the 32-bit case, this value will never
    520     // be used.
    521     in_lo = in;
    522   }
    523 
    524   if (isR6) {
    525     // We don't have an instruction to count the number of trailing zeroes.
    526     // Start by flipping the bits end-for-end so we can count the number of
    527     // leading zeroes instead.
    528     __ Rotr(out, in, 16);
    529     __ Wsbh(out, out);
    530     __ Bitswap(out, out);
    531     __ ClzR6(out, out);
    532   } else {
    533     // Convert trailing zeroes to trailing ones, and bits to their left
    534     // to zeroes.
    535     __ Addiu(TMP, in, -1);
    536     __ Xor(out, TMP, in);
    537     __ And(out, out, TMP);
    538     // Count number of leading zeroes.
    539     __ ClzR2(out, out);
    540     // Subtract number of leading zeroes from 32 to get number of trailing ones.
    541     // Remember that the trailing ones were formerly trailing zeroes.
    542     __ LoadConst32(TMP, 32);
    543     __ Subu(out, TMP, out);
    544   }
    545 
    546   if (is64bit) {
    547     // If in_lo is zero, then we counted the number of trailing zeroes in in_hi so we must add the
    548     // number of trailing zeroes in in_lo (32) to get the correct final count
    549     __ LoadConst32(TMP, 32);
    550     if (isR6) {
    551       __ Seleqz(TMP, TMP, in_lo);
    552     } else {
    553       __ Movn(TMP, ZERO, in_lo);
    554     }
    555     __ Addu(out, out, TMP);
    556   }
    557 }
    558 
    559 // int java.lang.Integer.numberOfTrailingZeros(int i)
    560 void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
    561   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
    562 }
    563 
    564 void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
    565   GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ false, IsR6(), GetAssembler());
    566 }
    567 
    568 // int java.lang.Long.numberOfTrailingZeros(long i)
    569 void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
    570   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
    571 }
    572 
    573 void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
    574   GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ true, IsR6(), GetAssembler());
    575 }
    576 
    577 // int java.lang.Integer.reverse(int)
    578 void IntrinsicLocationsBuilderMIPS::VisitIntegerReverse(HInvoke* invoke) {
    579   CreateIntToIntLocations(arena_, invoke);
    580 }
    581 
    582 void IntrinsicCodeGeneratorMIPS::VisitIntegerReverse(HInvoke* invoke) {
    583   GenReverse(invoke->GetLocations(),
    584              Primitive::kPrimInt,
    585              IsR2OrNewer(),
    586              IsR6(),
    587              /* reverseBits */ true,
    588              GetAssembler());
    589 }
    590 
    591 // long java.lang.Long.reverse(long)
    592 void IntrinsicLocationsBuilderMIPS::VisitLongReverse(HInvoke* invoke) {
    593   CreateIntToIntLocations(arena_, invoke);
    594 }
    595 
    596 void IntrinsicCodeGeneratorMIPS::VisitLongReverse(HInvoke* invoke) {
    597   GenReverse(invoke->GetLocations(),
    598              Primitive::kPrimLong,
    599              IsR2OrNewer(),
    600              IsR6(),
    601              /* reverseBits */ true,
    602              GetAssembler());
    603 }
    604 
    605 static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
    606   LocationSummary* locations = new (arena) LocationSummary(invoke,
    607                                                            LocationSummary::kNoCall,
    608                                                            kIntrinsified);
    609   locations->SetInAt(0, Location::RequiresFpuRegister());
    610   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    611 }
    612 
    613 static void GenBitCount(LocationSummary* locations,
    614                         Primitive::Type type,
    615                         bool isR6,
    616                         MipsAssembler* assembler) {
    617   Register out = locations->Out().AsRegister<Register>();
    618 
    619   // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
    620   //
    621   // A generalization of the best bit counting method to integers of
    622   // bit-widths up to 128 (parameterized by type T) is this:
    623   //
    624   // v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
    625   // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
    626   // v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
    627   // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; // count
    628   //
    629   // For comparison, for 32-bit quantities, this algorithm can be executed
    630   // using 20 MIPS instructions (the calls to LoadConst32() generate two
    631   // machine instructions each for the values being used in this algorithm).
    632   // A(n unrolled) loop-based algorithm required 25 instructions.
    633   //
    634   // For 64-bit quantities, this algorithm gets executed twice, (once
    635   // for in_lo, and again for in_hi), but saves a few instructions
    636   // because the mask values only have to be loaded once.  Using this
    637   // algorithm the count for a 64-bit operand can be performed in 29
    638   // instructions compared to a loop-based algorithm which required 47
    639   // instructions.
    640 
    641   if (type == Primitive::kPrimInt) {
    642     Register in = locations->InAt(0).AsRegister<Register>();
    643 
    644     __ Srl(TMP, in, 1);
    645     __ LoadConst32(AT, 0x55555555);
    646     __ And(TMP, TMP, AT);
    647     __ Subu(TMP, in, TMP);
    648     __ LoadConst32(AT, 0x33333333);
    649     __ And(out, TMP, AT);
    650     __ Srl(TMP, TMP, 2);
    651     __ And(TMP, TMP, AT);
    652     __ Addu(TMP, out, TMP);
    653     __ Srl(out, TMP, 4);
    654     __ Addu(out, out, TMP);
    655     __ LoadConst32(AT, 0x0F0F0F0F);
    656     __ And(out, out, AT);
    657     __ LoadConst32(TMP, 0x01010101);
    658     if (isR6) {
    659       __ MulR6(out, out, TMP);
    660     } else {
    661       __ MulR2(out, out, TMP);
    662     }
    663     __ Srl(out, out, 24);
    664   } else {
    665     DCHECK_EQ(type, Primitive::kPrimLong);
    666     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
    667     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
    668     Register tmp_hi = locations->GetTemp(0).AsRegister<Register>();
    669     Register out_hi = locations->GetTemp(1).AsRegister<Register>();
    670     Register tmp_lo = TMP;
    671     Register out_lo = out;
    672 
    673     __ Srl(tmp_lo, in_lo, 1);
    674     __ Srl(tmp_hi, in_hi, 1);
    675 
    676     __ LoadConst32(AT, 0x55555555);
    677 
    678     __ And(tmp_lo, tmp_lo, AT);
    679     __ Subu(tmp_lo, in_lo, tmp_lo);
    680 
    681     __ And(tmp_hi, tmp_hi, AT);
    682     __ Subu(tmp_hi, in_hi, tmp_hi);
    683 
    684     __ LoadConst32(AT, 0x33333333);
    685 
    686     __ And(out_lo, tmp_lo, AT);
    687     __ Srl(tmp_lo, tmp_lo, 2);
    688     __ And(tmp_lo, tmp_lo, AT);
    689     __ Addu(tmp_lo, out_lo, tmp_lo);
    690 
    691     __ And(out_hi, tmp_hi, AT);
    692     __ Srl(tmp_hi, tmp_hi, 2);
    693     __ And(tmp_hi, tmp_hi, AT);
    694     __ Addu(tmp_hi, out_hi, tmp_hi);
    695 
    696     // Here we deviate from the original algorithm a bit. We've reached
    697     // the stage where the bitfields holding the subtotals are large
    698     // enough to hold the combined subtotals for both the low word, and
    699     // the high word. This means that we can add the subtotals for the
    700     // the high, and low words into a single word, and compute the final
    701     // result for both the high, and low words using fewer instructions.
    702     __ LoadConst32(AT, 0x0F0F0F0F);
    703 
    704     __ Addu(TMP, tmp_hi, tmp_lo);
    705 
    706     __ Srl(out, TMP, 4);
    707     __ And(out, out, AT);
    708     __ And(TMP, TMP, AT);
    709     __ Addu(out, out, TMP);
    710 
    711     __ LoadConst32(AT, 0x01010101);
    712 
    713     if (isR6) {
    714       __ MulR6(out, out, AT);
    715     } else {
    716       __ MulR2(out, out, AT);
    717     }
    718 
    719     __ Srl(out, out, 24);
    720   }
    721 }
    722 
    723 // int java.lang.Integer.bitCount(int)
    724 void IntrinsicLocationsBuilderMIPS::VisitIntegerBitCount(HInvoke* invoke) {
    725   CreateIntToIntLocations(arena_, invoke);
    726 }
    727 
    728 void IntrinsicCodeGeneratorMIPS::VisitIntegerBitCount(HInvoke* invoke) {
    729   GenBitCount(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
    730 }
    731 
    732 // int java.lang.Long.bitCount(int)
    733 void IntrinsicLocationsBuilderMIPS::VisitLongBitCount(HInvoke* invoke) {
    734   LocationSummary* locations = new (arena_) LocationSummary(invoke,
    735                                                             LocationSummary::kNoCall,
    736                                                             kIntrinsified);
    737   locations->SetInAt(0, Location::RequiresRegister());
    738   locations->SetOut(Location::RequiresRegister());
    739   locations->AddTemp(Location::RequiresRegister());
    740   locations->AddTemp(Location::RequiresRegister());
    741 }
    742 
    743 void IntrinsicCodeGeneratorMIPS::VisitLongBitCount(HInvoke* invoke) {
    744   GenBitCount(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
    745 }
    746 
    747 static void MathAbsFP(LocationSummary* locations,
    748                       bool is64bit,
    749                       bool isR2OrNewer,
    750                       bool isR6,
    751                       MipsAssembler* assembler) {
    752   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
    753   FRegister out = locations->Out().AsFpuRegister<FRegister>();
    754 
    755   // Note, as a "quality of implementation", rather than pure "spec compliance", we require that
    756   // Math.abs() clears the sign bit (but changes nothing else) for all numbers, including NaN
    757   // (signaling NaN may become quiet though).
    758   //
    759   // The ABS.fmt instructions (abs.s and abs.d) do exactly that when NAN2008=1 (R6). For this case,
    760   // both regular floating point numbers and NAN values are treated alike, only the sign bit is
    761   // affected by this instruction.
    762   // But when NAN2008=0 (R2 and before), the ABS.fmt instructions can't be used. For this case, any
    763   // NaN operand signals invalid operation. This means that other bits (not just sign bit) might be
    764   // changed when doing abs(NaN). Because of that, we clear sign bit in a different way.
    765   if (isR6) {
    766     if (is64bit) {
    767       __ AbsD(out, in);
    768     } else {
    769       __ AbsS(out, in);
    770     }
    771   } else {
    772     if (is64bit) {
    773       if (in != out) {
    774         __ MovD(out, in);
    775       }
    776       __ MoveFromFpuHigh(TMP, in);
    777       // ins instruction is not available for R1.
    778       if (isR2OrNewer) {
    779         __ Ins(TMP, ZERO, 31, 1);
    780       } else {
    781         __ Sll(TMP, TMP, 1);
    782         __ Srl(TMP, TMP, 1);
    783       }
    784       __ MoveToFpuHigh(TMP, out);
    785     } else {
    786       __ Mfc1(TMP, in);
    787       // ins instruction is not available for R1.
    788       if (isR2OrNewer) {
    789         __ Ins(TMP, ZERO, 31, 1);
    790       } else {
    791         __ Sll(TMP, TMP, 1);
    792         __ Srl(TMP, TMP, 1);
    793       }
    794       __ Mtc1(TMP, out);
    795     }
    796   }
    797 }
    798 
    799 // double java.lang.Math.abs(double)
    800 void IntrinsicLocationsBuilderMIPS::VisitMathAbsDouble(HInvoke* invoke) {
    801   CreateFPToFPLocations(arena_, invoke);
    802 }
    803 
    804 void IntrinsicCodeGeneratorMIPS::VisitMathAbsDouble(HInvoke* invoke) {
    805   MathAbsFP(invoke->GetLocations(), /* is64bit */ true, IsR2OrNewer(), IsR6(), GetAssembler());
    806 }
    807 
    808 // float java.lang.Math.abs(float)
    809 void IntrinsicLocationsBuilderMIPS::VisitMathAbsFloat(HInvoke* invoke) {
    810   CreateFPToFPLocations(arena_, invoke);
    811 }
    812 
    813 void IntrinsicCodeGeneratorMIPS::VisitMathAbsFloat(HInvoke* invoke) {
    814   MathAbsFP(invoke->GetLocations(), /* is64bit */ false, IsR2OrNewer(), IsR6(), GetAssembler());
    815 }
    816 
    817 static void GenAbsInteger(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
    818   if (is64bit) {
    819     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
    820     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
    821     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
    822     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
    823 
    824     // The comments in this section show the analogous operations which would
    825     // be performed if we had 64-bit registers "in", and "out".
    826     // __ Dsra32(AT, in, 31);
    827     __ Sra(AT, in_hi, 31);
    828     // __ Xor(out, in, AT);
    829     __ Xor(TMP, in_lo, AT);
    830     __ Xor(out_hi, in_hi, AT);
    831     // __ Dsubu(out, out, AT);
    832     __ Subu(out_lo, TMP, AT);
    833     __ Sltu(TMP, out_lo, TMP);
    834     __ Addu(out_hi, out_hi, TMP);
    835   } else {
    836     Register in = locations->InAt(0).AsRegister<Register>();
    837     Register out = locations->Out().AsRegister<Register>();
    838 
    839     __ Sra(AT, in, 31);
    840     __ Xor(out, in, AT);
    841     __ Subu(out, out, AT);
    842   }
    843 }
    844 
    845 // int java.lang.Math.abs(int)
    846 void IntrinsicLocationsBuilderMIPS::VisitMathAbsInt(HInvoke* invoke) {
    847   CreateIntToIntLocations(arena_, invoke);
    848 }
    849 
    850 void IntrinsicCodeGeneratorMIPS::VisitMathAbsInt(HInvoke* invoke) {
    851   GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
    852 }
    853 
    854 // long java.lang.Math.abs(long)
    855 void IntrinsicLocationsBuilderMIPS::VisitMathAbsLong(HInvoke* invoke) {
    856   CreateIntToIntLocations(arena_, invoke);
    857 }
    858 
    859 void IntrinsicCodeGeneratorMIPS::VisitMathAbsLong(HInvoke* invoke) {
    860   GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
    861 }
    862 
    863 static void GenMinMaxFP(LocationSummary* locations,
    864                         bool is_min,
    865                         Primitive::Type type,
    866                         bool is_R6,
    867                         MipsAssembler* assembler) {
    868   FRegister out = locations->Out().AsFpuRegister<FRegister>();
    869   FRegister a = locations->InAt(0).AsFpuRegister<FRegister>();
    870   FRegister b = locations->InAt(1).AsFpuRegister<FRegister>();
    871 
    872   if (is_R6) {
    873     MipsLabel noNaNs;
    874     MipsLabel done;
    875     FRegister ftmp = ((out != a) && (out != b)) ? out : FTMP;
    876 
    877     // When Java computes min/max it prefers a NaN to a number; the
    878     // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of
    879     // the inputs is a NaN and the other is a valid number, the MIPS
    880     // instruction will return the number; Java wants the NaN value
    881     // returned. This is why there is extra logic preceding the use of
    882     // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
    883     // NaN, return the NaN, otherwise return the min/max.
    884     if (type == Primitive::kPrimDouble) {
    885       __ CmpUnD(FTMP, a, b);
    886       __ Bc1eqz(FTMP, &noNaNs);
    887 
    888       // One of the inputs is a NaN
    889       __ CmpEqD(ftmp, a, a);
    890       // If a == a then b is the NaN, otherwise a is the NaN.
    891       __ SelD(ftmp, a, b);
    892 
    893       if (ftmp != out) {
    894         __ MovD(out, ftmp);
    895       }
    896 
    897       __ B(&done);
    898 
    899       __ Bind(&noNaNs);
    900 
    901       if (is_min) {
    902         __ MinD(out, a, b);
    903       } else {
    904         __ MaxD(out, a, b);
    905       }
    906     } else {
    907       DCHECK_EQ(type, Primitive::kPrimFloat);
    908       __ CmpUnS(FTMP, a, b);
    909       __ Bc1eqz(FTMP, &noNaNs);
    910 
    911       // One of the inputs is a NaN
    912       __ CmpEqS(ftmp, a, a);
    913       // If a == a then b is the NaN, otherwise a is the NaN.
    914       __ SelS(ftmp, a, b);
    915 
    916       if (ftmp != out) {
    917         __ MovS(out, ftmp);
    918       }
    919 
    920       __ B(&done);
    921 
    922       __ Bind(&noNaNs);
    923 
    924       if (is_min) {
    925         __ MinS(out, a, b);
    926       } else {
    927         __ MaxS(out, a, b);
    928       }
    929     }
    930 
    931     __ Bind(&done);
    932   } else {
    933     MipsLabel ordered;
    934     MipsLabel compare;
    935     MipsLabel select;
    936     MipsLabel done;
    937 
    938     if (type == Primitive::kPrimDouble) {
    939       __ CunD(a, b);
    940     } else {
    941       DCHECK_EQ(type, Primitive::kPrimFloat);
    942       __ CunS(a, b);
    943     }
    944     __ Bc1f(&ordered);
    945 
    946     // a or b (or both) is a NaN. Return one, which is a NaN.
    947     if (type == Primitive::kPrimDouble) {
    948       __ CeqD(b, b);
    949     } else {
    950       __ CeqS(b, b);
    951     }
    952     __ B(&select);
    953 
    954     __ Bind(&ordered);
    955 
    956     // Neither is a NaN.
    957     // a == b? (-0.0 compares equal with +0.0)
    958     // If equal, handle zeroes, else compare further.
    959     if (type == Primitive::kPrimDouble) {
    960       __ CeqD(a, b);
    961     } else {
    962       __ CeqS(a, b);
    963     }
    964     __ Bc1f(&compare);
    965 
    966     // a == b either bit for bit or one is -0.0 and the other is +0.0.
    967     if (type == Primitive::kPrimDouble) {
    968       __ MoveFromFpuHigh(TMP, a);
    969       __ MoveFromFpuHigh(AT, b);
    970     } else {
    971       __ Mfc1(TMP, a);
    972       __ Mfc1(AT, b);
    973     }
    974 
    975     if (is_min) {
    976       // -0.0 prevails over +0.0.
    977       __ Or(TMP, TMP, AT);
    978     } else {
    979       // +0.0 prevails over -0.0.
    980       __ And(TMP, TMP, AT);
    981     }
    982 
    983     if (type == Primitive::kPrimDouble) {
    984       __ Mfc1(AT, a);
    985       __ Mtc1(AT, out);
    986       __ MoveToFpuHigh(TMP, out);
    987     } else {
    988       __ Mtc1(TMP, out);
    989     }
    990     __ B(&done);
    991 
    992     __ Bind(&compare);
    993 
    994     if (type == Primitive::kPrimDouble) {
    995       if (is_min) {
    996         // return (a <= b) ? a : b;
    997         __ ColeD(a, b);
    998       } else {
    999         // return (a >= b) ? a : b;
   1000         __ ColeD(b, a);  // b <= a
   1001       }
   1002     } else {
   1003       if (is_min) {
   1004         // return (a <= b) ? a : b;
   1005         __ ColeS(a, b);
   1006       } else {
   1007         // return (a >= b) ? a : b;
   1008         __ ColeS(b, a);  // b <= a
   1009       }
   1010     }
   1011 
   1012     __ Bind(&select);
   1013 
   1014     if (type == Primitive::kPrimDouble) {
   1015       __ MovtD(out, a);
   1016       __ MovfD(out, b);
   1017     } else {
   1018       __ MovtS(out, a);
   1019       __ MovfS(out, b);
   1020     }
   1021 
   1022     __ Bind(&done);
   1023   }
   1024 }
   1025 
   1026 static void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
   1027   LocationSummary* locations = new (arena) LocationSummary(invoke,
   1028                                                            LocationSummary::kNoCall,
   1029                                                            kIntrinsified);
   1030   locations->SetInAt(0, Location::RequiresFpuRegister());
   1031   locations->SetInAt(1, Location::RequiresFpuRegister());
   1032   locations->SetOut(Location::RequiresFpuRegister(), Location::kOutputOverlap);
   1033 }
   1034 
   1035 // double java.lang.Math.min(double, double)
   1036 void IntrinsicLocationsBuilderMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) {
   1037   CreateFPFPToFPLocations(arena_, invoke);
   1038 }
   1039 
   1040 void IntrinsicCodeGeneratorMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) {
   1041   GenMinMaxFP(invoke->GetLocations(),
   1042               /* is_min */ true,
   1043               Primitive::kPrimDouble,
   1044               IsR6(),
   1045               GetAssembler());
   1046 }
   1047 
   1048 // float java.lang.Math.min(float, float)
   1049 void IntrinsicLocationsBuilderMIPS::VisitMathMinFloatFloat(HInvoke* invoke) {
   1050   CreateFPFPToFPLocations(arena_, invoke);
   1051 }
   1052 
   1053 void IntrinsicCodeGeneratorMIPS::VisitMathMinFloatFloat(HInvoke* invoke) {
   1054   GenMinMaxFP(invoke->GetLocations(),
   1055               /* is_min */ true,
   1056               Primitive::kPrimFloat,
   1057               IsR6(),
   1058               GetAssembler());
   1059 }
   1060 
   1061 // double java.lang.Math.max(double, double)
   1062 void IntrinsicLocationsBuilderMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) {
   1063   CreateFPFPToFPLocations(arena_, invoke);
   1064 }
   1065 
   1066 void IntrinsicCodeGeneratorMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) {
   1067   GenMinMaxFP(invoke->GetLocations(),
   1068               /* is_min */ false,
   1069               Primitive::kPrimDouble,
   1070               IsR6(),
   1071               GetAssembler());
   1072 }
   1073 
   1074 // float java.lang.Math.max(float, float)
   1075 void IntrinsicLocationsBuilderMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) {
   1076   CreateFPFPToFPLocations(arena_, invoke);
   1077 }
   1078 
   1079 void IntrinsicCodeGeneratorMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) {
   1080   GenMinMaxFP(invoke->GetLocations(),
   1081               /* is_min */ false,
   1082               Primitive::kPrimFloat,
   1083               IsR6(),
   1084               GetAssembler());
   1085 }
   1086 
   1087 static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
   1088   LocationSummary* locations = new (arena) LocationSummary(invoke,
   1089                                                            LocationSummary::kNoCall,
   1090                                                            kIntrinsified);
   1091   locations->SetInAt(0, Location::RequiresRegister());
   1092   locations->SetInAt(1, Location::RequiresRegister());
   1093   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   1094 }
   1095 
   1096 static void GenMinMax(LocationSummary* locations,
   1097                       bool is_min,
   1098                       Primitive::Type type,
   1099                       bool is_R6,
   1100                       MipsAssembler* assembler) {
   1101   if (is_R6) {
   1102     // Some architectures, such as ARM and MIPS (prior to r6), have a
   1103     // conditional move instruction which only changes the target
   1104     // (output) register if the condition is true (MIPS prior to r6 had
   1105     // MOVF, MOVT, MOVN, and MOVZ). The SELEQZ and SELNEZ instructions
   1106     // always change the target (output) register.  If the condition is
   1107     // true the output register gets the contents of the "rs" register;
   1108     // otherwise, the output register is set to zero. One consequence
   1109     // of this is that to implement something like "rd = c==0 ? rs : rt"
   1110     // MIPS64r6 needs to use a pair of SELEQZ/SELNEZ instructions.
   1111     // After executing this pair of instructions one of the output
   1112     // registers from the pair will necessarily contain zero. Then the
   1113     // code ORs the output registers from the SELEQZ/SELNEZ instructions
   1114     // to get the final result.
   1115     //
   1116     // The initial test to see if the output register is same as the
   1117     // first input register is needed to make sure that value in the
   1118     // first input register isn't clobbered before we've finished
   1119     // computing the output value. The logic in the corresponding else
   1120     // clause performs the same task but makes sure the second input
   1121     // register isn't clobbered in the event that it's the same register
   1122     // as the output register; the else clause also handles the case
   1123     // where the output register is distinct from both the first, and the
   1124     // second input registers.
   1125     if (type == Primitive::kPrimLong) {
   1126       Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
   1127       Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
   1128       Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
   1129       Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
   1130       Register out_lo = locations->Out().AsRegisterPairLow<Register>();
   1131       Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
   1132 
   1133       MipsLabel compare_done;
   1134 
   1135       if (a_lo == b_lo) {
   1136         if (out_lo != a_lo) {
   1137           __ Move(out_lo, a_lo);
   1138           __ Move(out_hi, a_hi);
   1139         }
   1140       } else {
   1141         __ Slt(TMP, b_hi, a_hi);
   1142         __ Bne(b_hi, a_hi, &compare_done);
   1143 
   1144         __ Sltu(TMP, b_lo, a_lo);
   1145 
   1146         __ Bind(&compare_done);
   1147 
   1148         if (is_min) {
   1149           __ Seleqz(AT, a_lo, TMP);
   1150           __ Selnez(out_lo, b_lo, TMP);  // Safe even if out_lo == a_lo/b_lo
   1151                                          // because at this point we're
   1152                                          // done using a_lo/b_lo.
   1153         } else {
   1154           __ Selnez(AT, a_lo, TMP);
   1155           __ Seleqz(out_lo, b_lo, TMP);  // ditto
   1156         }
   1157         __ Or(out_lo, out_lo, AT);
   1158         if (is_min) {
   1159           __ Seleqz(AT, a_hi, TMP);
   1160           __ Selnez(out_hi, b_hi, TMP);  // ditto but for out_hi & a_hi/b_hi
   1161         } else {
   1162           __ Selnez(AT, a_hi, TMP);
   1163           __ Seleqz(out_hi, b_hi, TMP);  // ditto but for out_hi & a_hi/b_hi
   1164         }
   1165         __ Or(out_hi, out_hi, AT);
   1166       }
   1167     } else {
   1168       DCHECK_EQ(type, Primitive::kPrimInt);
   1169       Register a = locations->InAt(0).AsRegister<Register>();
   1170       Register b = locations->InAt(1).AsRegister<Register>();
   1171       Register out = locations->Out().AsRegister<Register>();
   1172 
   1173       if (a == b) {
   1174         if (out != a) {
   1175           __ Move(out, a);
   1176         }
   1177       } else {
   1178         __ Slt(AT, b, a);
   1179         if (is_min) {
   1180           __ Seleqz(TMP, a, AT);
   1181           __ Selnez(AT, b, AT);
   1182         } else {
   1183           __ Selnez(TMP, a, AT);
   1184           __ Seleqz(AT, b, AT);
   1185         }
   1186         __ Or(out, TMP, AT);
   1187       }
   1188     }
   1189   } else {
   1190     if (type == Primitive::kPrimLong) {
   1191       Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
   1192       Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
   1193       Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
   1194       Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
   1195       Register out_lo = locations->Out().AsRegisterPairLow<Register>();
   1196       Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
   1197 
   1198       MipsLabel compare_done;
   1199 
   1200       if (a_lo == b_lo) {
   1201         if (out_lo != a_lo) {
   1202           __ Move(out_lo, a_lo);
   1203           __ Move(out_hi, a_hi);
   1204         }
   1205       } else {
   1206         __ Slt(TMP, a_hi, b_hi);
   1207         __ Bne(a_hi, b_hi, &compare_done);
   1208 
   1209         __ Sltu(TMP, a_lo, b_lo);
   1210 
   1211         __ Bind(&compare_done);
   1212 
   1213         if (is_min) {
   1214           if (out_lo != a_lo) {
   1215             __ Movn(out_hi, a_hi, TMP);
   1216             __ Movn(out_lo, a_lo, TMP);
   1217           }
   1218           if (out_lo != b_lo) {
   1219             __ Movz(out_hi, b_hi, TMP);
   1220             __ Movz(out_lo, b_lo, TMP);
   1221           }
   1222         } else {
   1223           if (out_lo != a_lo) {
   1224             __ Movz(out_hi, a_hi, TMP);
   1225             __ Movz(out_lo, a_lo, TMP);
   1226           }
   1227           if (out_lo != b_lo) {
   1228             __ Movn(out_hi, b_hi, TMP);
   1229             __ Movn(out_lo, b_lo, TMP);
   1230           }
   1231         }
   1232       }
   1233     } else {
   1234       DCHECK_EQ(type, Primitive::kPrimInt);
   1235       Register a = locations->InAt(0).AsRegister<Register>();
   1236       Register b = locations->InAt(1).AsRegister<Register>();
   1237       Register out = locations->Out().AsRegister<Register>();
   1238 
   1239       if (a == b) {
   1240         if (out != a) {
   1241           __ Move(out, a);
   1242         }
   1243       } else {
   1244         __ Slt(AT, a, b);
   1245         if (is_min) {
   1246           if (out != a) {
   1247             __ Movn(out, a, AT);
   1248           }
   1249           if (out != b) {
   1250             __ Movz(out, b, AT);
   1251           }
   1252         } else {
   1253           if (out != a) {
   1254             __ Movz(out, a, AT);
   1255           }
   1256           if (out != b) {
   1257             __ Movn(out, b, AT);
   1258           }
   1259         }
   1260       }
   1261     }
   1262   }
   1263 }
   1264 
   1265 // int java.lang.Math.min(int, int)
   1266 void IntrinsicLocationsBuilderMIPS::VisitMathMinIntInt(HInvoke* invoke) {
   1267   CreateIntIntToIntLocations(arena_, invoke);
   1268 }
   1269 
   1270 void IntrinsicCodeGeneratorMIPS::VisitMathMinIntInt(HInvoke* invoke) {
   1271   GenMinMax(invoke->GetLocations(),
   1272             /* is_min */ true,
   1273             Primitive::kPrimInt,
   1274             IsR6(),
   1275             GetAssembler());
   1276 }
   1277 
   1278 // long java.lang.Math.min(long, long)
   1279 void IntrinsicLocationsBuilderMIPS::VisitMathMinLongLong(HInvoke* invoke) {
   1280   CreateIntIntToIntLocations(arena_, invoke);
   1281 }
   1282 
   1283 void IntrinsicCodeGeneratorMIPS::VisitMathMinLongLong(HInvoke* invoke) {
   1284   GenMinMax(invoke->GetLocations(),
   1285             /* is_min */ true,
   1286             Primitive::kPrimLong,
   1287             IsR6(),
   1288             GetAssembler());
   1289 }
   1290 
   1291 // int java.lang.Math.max(int, int)
   1292 void IntrinsicLocationsBuilderMIPS::VisitMathMaxIntInt(HInvoke* invoke) {
   1293   CreateIntIntToIntLocations(arena_, invoke);
   1294 }
   1295 
   1296 void IntrinsicCodeGeneratorMIPS::VisitMathMaxIntInt(HInvoke* invoke) {
   1297   GenMinMax(invoke->GetLocations(),
   1298             /* is_min */ false,
   1299             Primitive::kPrimInt,
   1300             IsR6(),
   1301             GetAssembler());
   1302 }
   1303 
   1304 // long java.lang.Math.max(long, long)
   1305 void IntrinsicLocationsBuilderMIPS::VisitMathMaxLongLong(HInvoke* invoke) {
   1306   CreateIntIntToIntLocations(arena_, invoke);
   1307 }
   1308 
   1309 void IntrinsicCodeGeneratorMIPS::VisitMathMaxLongLong(HInvoke* invoke) {
   1310   GenMinMax(invoke->GetLocations(),
   1311             /* is_min */ false,
   1312             Primitive::kPrimLong,
   1313             IsR6(),
   1314             GetAssembler());
   1315 }
   1316 
   1317 // double java.lang.Math.sqrt(double)
   1318 void IntrinsicLocationsBuilderMIPS::VisitMathSqrt(HInvoke* invoke) {
   1319   CreateFPToFPLocations(arena_, invoke);
   1320 }
   1321 
   1322 void IntrinsicCodeGeneratorMIPS::VisitMathSqrt(HInvoke* invoke) {
   1323   LocationSummary* locations = invoke->GetLocations();
   1324   MipsAssembler* assembler = GetAssembler();
   1325   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
   1326   FRegister out = locations->Out().AsFpuRegister<FRegister>();
   1327 
   1328   __ SqrtD(out, in);
   1329 }
   1330 
   1331 // byte libcore.io.Memory.peekByte(long address)
   1332 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
   1333   CreateIntToIntLocations(arena_, invoke);
   1334 }
   1335 
   1336 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
   1337   MipsAssembler* assembler = GetAssembler();
   1338   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1339   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
   1340 
   1341   __ Lb(out, adr, 0);
   1342 }
   1343 
   1344 // short libcore.io.Memory.peekShort(long address)
   1345 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
   1346   CreateIntToIntLocations(arena_, invoke);
   1347 }
   1348 
   1349 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
   1350   MipsAssembler* assembler = GetAssembler();
   1351   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1352   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
   1353 
   1354   if (IsR6()) {
   1355     __ Lh(out, adr, 0);
   1356   } else if (IsR2OrNewer()) {
   1357     // Unlike for words, there are no lhl/lhr instructions to load
   1358     // unaligned halfwords so the code loads individual bytes, in case
   1359     // the address isn't halfword-aligned, and assembles them into a
   1360     // signed halfword.
   1361     __ Lb(AT, adr, 1);   // This byte must be sign-extended.
   1362     __ Lb(out, adr, 0);  // This byte can be either sign-extended, or
   1363                          // zero-extended because the following
   1364                          // instruction overwrites the sign bits.
   1365     __ Ins(out, AT, 8, 24);
   1366   } else {
   1367     __ Lbu(AT, adr, 0);  // This byte must be zero-extended.  If it's not
   1368                          // the "or" instruction below will destroy the upper
   1369                          // 24 bits of the final result.
   1370     __ Lb(out, adr, 1);  // This byte must be sign-extended.
   1371     __ Sll(out, out, 8);
   1372     __ Or(out, out, AT);
   1373   }
   1374 }
   1375 
   1376 // int libcore.io.Memory.peekInt(long address)
   1377 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
   1378   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
   1379 }
   1380 
   1381 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
   1382   MipsAssembler* assembler = GetAssembler();
   1383   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1384   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
   1385 
   1386   if (IsR6()) {
   1387     __ Lw(out, adr, 0);
   1388   } else {
   1389     __ Lwr(out, adr, 0);
   1390     __ Lwl(out, adr, 3);
   1391   }
   1392 }
   1393 
   1394 // long libcore.io.Memory.peekLong(long address)
   1395 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
   1396   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
   1397 }
   1398 
   1399 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
   1400   MipsAssembler* assembler = GetAssembler();
   1401   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1402   Register out_lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>();
   1403   Register out_hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>();
   1404 
   1405   if (IsR6()) {
   1406     __ Lw(out_lo, adr, 0);
   1407     __ Lw(out_hi, adr, 4);
   1408   } else {
   1409     __ Lwr(out_lo, adr, 0);
   1410     __ Lwl(out_lo, adr, 3);
   1411     __ Lwr(out_hi, adr, 4);
   1412     __ Lwl(out_hi, adr, 7);
   1413   }
   1414 }
   1415 
   1416 static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
   1417   LocationSummary* locations = new (arena) LocationSummary(invoke,
   1418                                                            LocationSummary::kNoCall,
   1419                                                            kIntrinsified);
   1420   locations->SetInAt(0, Location::RequiresRegister());
   1421   locations->SetInAt(1, Location::RequiresRegister());
   1422 }
   1423 
   1424 // void libcore.io.Memory.pokeByte(long address, byte value)
   1425 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
   1426   CreateIntIntToVoidLocations(arena_, invoke);
   1427 }
   1428 
   1429 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
   1430   MipsAssembler* assembler = GetAssembler();
   1431   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1432   Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
   1433 
   1434   __ Sb(val, adr, 0);
   1435 }
   1436 
   1437 // void libcore.io.Memory.pokeShort(long address, short value)
   1438 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
   1439   CreateIntIntToVoidLocations(arena_, invoke);
   1440 }
   1441 
   1442 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
   1443   MipsAssembler* assembler = GetAssembler();
   1444   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1445   Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
   1446 
   1447   if (IsR6()) {
   1448     __ Sh(val, adr, 0);
   1449   } else {
   1450     // Unlike for words, there are no shl/shr instructions to store
   1451     // unaligned halfwords so the code stores individual bytes, in case
   1452     // the address isn't halfword-aligned.
   1453     __ Sb(val, adr, 0);
   1454     __ Srl(AT, val, 8);
   1455     __ Sb(AT, adr, 1);
   1456   }
   1457 }
   1458 
   1459 // void libcore.io.Memory.pokeInt(long address, int value)
   1460 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
   1461   CreateIntIntToVoidLocations(arena_, invoke);
   1462 }
   1463 
   1464 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
   1465   MipsAssembler* assembler = GetAssembler();
   1466   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1467   Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
   1468 
   1469   if (IsR6()) {
   1470     __ Sw(val, adr, 0);
   1471   } else {
   1472     __ Swr(val, adr, 0);
   1473     __ Swl(val, adr, 3);
   1474   }
   1475 }
   1476 
   1477 // void libcore.io.Memory.pokeLong(long address, long value)
   1478 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
   1479   CreateIntIntToVoidLocations(arena_, invoke);
   1480 }
   1481 
   1482 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
   1483   MipsAssembler* assembler = GetAssembler();
   1484   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
   1485   Register val_lo = invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>();
   1486   Register val_hi = invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>();
   1487 
   1488   if (IsR6()) {
   1489     __ Sw(val_lo, adr, 0);
   1490     __ Sw(val_hi, adr, 4);
   1491   } else {
   1492     __ Swr(val_lo, adr, 0);
   1493     __ Swl(val_lo, adr, 3);
   1494     __ Swr(val_hi, adr, 4);
   1495     __ Swl(val_hi, adr, 7);
   1496   }
   1497 }
   1498 
   1499 // Thread java.lang.Thread.currentThread()
   1500 void IntrinsicLocationsBuilderMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
   1501   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   1502                                                             LocationSummary::kNoCall,
   1503                                                             kIntrinsified);
   1504   locations->SetOut(Location::RequiresRegister());
   1505 }
   1506 
   1507 void IntrinsicCodeGeneratorMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
   1508   MipsAssembler* assembler = GetAssembler();
   1509   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
   1510 
   1511   __ LoadFromOffset(kLoadWord,
   1512                     out,
   1513                     TR,
   1514                     Thread::PeerOffset<kMipsPointerSize>().Int32Value());
   1515 }
   1516 
   1517 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
   1518                                           HInvoke* invoke,
   1519                                           Primitive::Type type) {
   1520   bool can_call = kEmitCompilerReadBarrier &&
   1521       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
   1522        invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
   1523   LocationSummary* locations = new (arena) LocationSummary(invoke,
   1524                                                            (can_call
   1525                                                                 ? LocationSummary::kCallOnSlowPath
   1526                                                                 : LocationSummary::kNoCall),
   1527                                                            kIntrinsified);
   1528   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   1529   locations->SetInAt(1, Location::RequiresRegister());
   1530   locations->SetInAt(2, Location::RequiresRegister());
   1531   locations->SetOut(Location::RequiresRegister(),
   1532                     (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
   1533   if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   1534     // We need a temporary register for the read barrier marking slow
   1535     // path in InstructionCodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier.
   1536     locations->AddTemp(Location::RequiresRegister());
   1537   }
   1538 }
   1539 
   1540 // Note that the caller must supply a properly aligned memory address.
   1541 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
   1542 static void GenUnsafeGet(HInvoke* invoke,
   1543                          Primitive::Type type,
   1544                          bool is_volatile,
   1545                          bool is_R6,
   1546                          CodeGeneratorMIPS* codegen) {
   1547   LocationSummary* locations = invoke->GetLocations();
   1548   DCHECK((type == Primitive::kPrimInt) ||
   1549          (type == Primitive::kPrimLong) ||
   1550          (type == Primitive::kPrimNot)) << type;
   1551   MipsAssembler* assembler = codegen->GetAssembler();
   1552   // Target register.
   1553   Location trg_loc = locations->Out();
   1554   // Object pointer.
   1555   Location base_loc = locations->InAt(1);
   1556   Register base = base_loc.AsRegister<Register>();
   1557   // The "offset" argument is passed as a "long". Since this code is for
   1558   // a 32-bit processor, we can only use 32-bit addresses, so we only
   1559   // need the low 32-bits of offset.
   1560   Location offset_loc = locations->InAt(2);
   1561   Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
   1562 
   1563   if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == Primitive::kPrimNot))) {
   1564     __ Addu(TMP, base, offset_lo);
   1565   }
   1566 
   1567   switch (type) {
   1568     case Primitive::kPrimLong: {
   1569       Register trg_lo = trg_loc.AsRegisterPairLow<Register>();
   1570       Register trg_hi = trg_loc.AsRegisterPairHigh<Register>();
   1571       CHECK(!is_volatile);  // TODO: support atomic 8-byte volatile loads.
   1572       if (is_R6) {
   1573         __ Lw(trg_lo, TMP, 0);
   1574         __ Lw(trg_hi, TMP, 4);
   1575       } else {
   1576         __ Lwr(trg_lo, TMP, 0);
   1577         __ Lwl(trg_lo, TMP, 3);
   1578         __ Lwr(trg_hi, TMP, 4);
   1579         __ Lwl(trg_hi, TMP, 7);
   1580       }
   1581       break;
   1582     }
   1583 
   1584     case Primitive::kPrimInt: {
   1585       Register trg = trg_loc.AsRegister<Register>();
   1586       if (is_R6) {
   1587         __ Lw(trg, TMP, 0);
   1588       } else {
   1589         __ Lwr(trg, TMP, 0);
   1590         __ Lwl(trg, TMP, 3);
   1591       }
   1592       if (is_volatile) {
   1593         __ Sync(0);
   1594       }
   1595       break;
   1596     }
   1597 
   1598     case Primitive::kPrimNot: {
   1599       Register trg = trg_loc.AsRegister<Register>();
   1600       if (kEmitCompilerReadBarrier) {
   1601         if (kUseBakerReadBarrier) {
   1602           Location temp = locations->GetTemp(0);
   1603           codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
   1604                                                              trg_loc,
   1605                                                              base,
   1606                                                              /* offset */ 0U,
   1607                                                              /* index */ offset_loc,
   1608                                                              TIMES_1,
   1609                                                              temp,
   1610                                                              /* needs_null_check */ false);
   1611           if (is_volatile) {
   1612             __ Sync(0);
   1613           }
   1614         } else {
   1615           if (is_R6) {
   1616             __ Lw(trg, TMP, 0);
   1617           } else {
   1618             __ Lwr(trg, TMP, 0);
   1619             __ Lwl(trg, TMP, 3);
   1620           }
   1621           if (is_volatile) {
   1622             __ Sync(0);
   1623           }
   1624           codegen->GenerateReadBarrierSlow(invoke,
   1625                                            trg_loc,
   1626                                            trg_loc,
   1627                                            base_loc,
   1628                                            /* offset */ 0U,
   1629                                            /* index */ offset_loc);
   1630         }
   1631       } else {
   1632         if (is_R6) {
   1633           __ Lw(trg, TMP, 0);
   1634         } else {
   1635           __ Lwr(trg, TMP, 0);
   1636           __ Lwl(trg, TMP, 3);
   1637         }
   1638         if (is_volatile) {
   1639           __ Sync(0);
   1640         }
   1641         __ MaybeUnpoisonHeapReference(trg);
   1642       }
   1643       break;
   1644     }
   1645 
   1646     default:
   1647       LOG(FATAL) << "Unexpected type " << type;
   1648       UNREACHABLE();
   1649   }
   1650 }
   1651 
   1652 // int sun.misc.Unsafe.getInt(Object o, long offset)
   1653 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGet(HInvoke* invoke) {
   1654   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
   1655 }
   1656 
   1657 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGet(HInvoke* invoke) {
   1658   GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, IsR6(), codegen_);
   1659 }
   1660 
   1661 // int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
   1662 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
   1663   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
   1664 }
   1665 
   1666 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
   1667   GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, IsR6(), codegen_);
   1668 }
   1669 
   1670 // long sun.misc.Unsafe.getLong(Object o, long offset)
   1671 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
   1672   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
   1673 }
   1674 
   1675 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
   1676   GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, IsR6(), codegen_);
   1677 }
   1678 
   1679 // Object sun.misc.Unsafe.getObject(Object o, long offset)
   1680 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
   1681   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
   1682 }
   1683 
   1684 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
   1685   GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, IsR6(), codegen_);
   1686 }
   1687 
   1688 // Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
   1689 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   1690   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
   1691 }
   1692 
   1693 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
   1694   GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, IsR6(), codegen_);
   1695 }
   1696 
   1697 static void CreateIntIntIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
   1698   LocationSummary* locations = new (arena) LocationSummary(invoke,
   1699                                                            LocationSummary::kNoCall,
   1700                                                            kIntrinsified);
   1701   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   1702   locations->SetInAt(1, Location::RequiresRegister());
   1703   locations->SetInAt(2, Location::RequiresRegister());
   1704   locations->SetInAt(3, Location::RequiresRegister());
   1705 }
   1706 
   1707 // Note that the caller must supply a properly aligned memory address.
   1708 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
   1709 static void GenUnsafePut(LocationSummary* locations,
   1710                          Primitive::Type type,
   1711                          bool is_volatile,
   1712                          bool is_ordered,
   1713                          bool is_R6,
   1714                          CodeGeneratorMIPS* codegen) {
   1715   DCHECK((type == Primitive::kPrimInt) ||
   1716          (type == Primitive::kPrimLong) ||
   1717          (type == Primitive::kPrimNot)) << type;
   1718   MipsAssembler* assembler = codegen->GetAssembler();
   1719   // Object pointer.
   1720   Register base = locations->InAt(1).AsRegister<Register>();
   1721   // The "offset" argument is passed as a "long", i.e., it's 64-bits in
   1722   // size. Since this code is for a 32-bit processor, we can only use
   1723   // 32-bit addresses, so we only need the low 32-bits of offset.
   1724   Register offset_lo = locations->InAt(2).AsRegisterPairLow<Register>();
   1725 
   1726   __ Addu(TMP, base, offset_lo);
   1727   if (is_volatile || is_ordered) {
   1728     __ Sync(0);
   1729   }
   1730   if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
   1731     Register value = locations->InAt(3).AsRegister<Register>();
   1732 
   1733     if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
   1734       __ PoisonHeapReference(AT, value);
   1735       value = AT;
   1736     }
   1737 
   1738     if (is_R6) {
   1739       __ Sw(value, TMP, 0);
   1740     } else {
   1741       __ Swr(value, TMP, 0);
   1742       __ Swl(value, TMP, 3);
   1743     }
   1744   } else {
   1745     Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>();
   1746     Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>();
   1747     CHECK(!is_volatile);  // TODO: support atomic 8-byte volatile stores.
   1748     if (is_R6) {
   1749       __ Sw(value_lo, TMP, 0);
   1750       __ Sw(value_hi, TMP, 4);
   1751     } else {
   1752       __ Swr(value_lo, TMP, 0);
   1753       __ Swl(value_lo, TMP, 3);
   1754       __ Swr(value_hi, TMP, 4);
   1755       __ Swl(value_hi, TMP, 7);
   1756     }
   1757   }
   1758 
   1759   if (is_volatile) {
   1760     __ Sync(0);
   1761   }
   1762 
   1763   if (type == Primitive::kPrimNot) {
   1764     bool value_can_be_null = true;  // TODO: Worth finding out this information?
   1765     codegen->MarkGCCard(base, locations->InAt(3).AsRegister<Register>(), value_can_be_null);
   1766   }
   1767 }
   1768 
   1769 // void sun.misc.Unsafe.putInt(Object o, long offset, int x)
   1770 void IntrinsicLocationsBuilderMIPS::VisitUnsafePut(HInvoke* invoke) {
   1771   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1772 }
   1773 
   1774 void IntrinsicCodeGeneratorMIPS::VisitUnsafePut(HInvoke* invoke) {
   1775   GenUnsafePut(invoke->GetLocations(),
   1776                Primitive::kPrimInt,
   1777                /* is_volatile */ false,
   1778                /* is_ordered */ false,
   1779                IsR6(),
   1780                codegen_);
   1781 }
   1782 
   1783 // void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x)
   1784 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
   1785   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1786 }
   1787 
   1788 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
   1789   GenUnsafePut(invoke->GetLocations(),
   1790                Primitive::kPrimInt,
   1791                /* is_volatile */ false,
   1792                /* is_ordered */ true,
   1793                IsR6(),
   1794                codegen_);
   1795 }
   1796 
   1797 // void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x)
   1798 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
   1799   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1800 }
   1801 
   1802 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
   1803   GenUnsafePut(invoke->GetLocations(),
   1804                Primitive::kPrimInt,
   1805                /* is_volatile */ true,
   1806                /* is_ordered */ false,
   1807                IsR6(),
   1808                codegen_);
   1809 }
   1810 
   1811 // void sun.misc.Unsafe.putObject(Object o, long offset, Object x)
   1812 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObject(HInvoke* invoke) {
   1813   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1814 }
   1815 
   1816 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObject(HInvoke* invoke) {
   1817   GenUnsafePut(invoke->GetLocations(),
   1818                Primitive::kPrimNot,
   1819                /* is_volatile */ false,
   1820                /* is_ordered */ false,
   1821                IsR6(),
   1822                codegen_);
   1823 }
   1824 
   1825 // void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x)
   1826 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   1827   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1828 }
   1829 
   1830 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
   1831   GenUnsafePut(invoke->GetLocations(),
   1832                Primitive::kPrimNot,
   1833                /* is_volatile */ false,
   1834                /* is_ordered */ true,
   1835                IsR6(),
   1836                codegen_);
   1837 }
   1838 
   1839 // void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x)
   1840 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   1841   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1842 }
   1843 
   1844 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
   1845   GenUnsafePut(invoke->GetLocations(),
   1846                Primitive::kPrimNot,
   1847                /* is_volatile */ true,
   1848                /* is_ordered */ false,
   1849                IsR6(),
   1850                codegen_);
   1851 }
   1852 
   1853 // void sun.misc.Unsafe.putLong(Object o, long offset, long x)
   1854 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLong(HInvoke* invoke) {
   1855   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1856 }
   1857 
   1858 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLong(HInvoke* invoke) {
   1859   GenUnsafePut(invoke->GetLocations(),
   1860                Primitive::kPrimLong,
   1861                /* is_volatile */ false,
   1862                /* is_ordered */ false,
   1863                IsR6(),
   1864                codegen_);
   1865 }
   1866 
   1867 // void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x)
   1868 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   1869   CreateIntIntIntIntToVoidLocations(arena_, invoke);
   1870 }
   1871 
   1872 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
   1873   GenUnsafePut(invoke->GetLocations(),
   1874                Primitive::kPrimLong,
   1875                /* is_volatile */ false,
   1876                /* is_ordered */ true,
   1877                IsR6(),
   1878                codegen_);
   1879 }
   1880 
   1881 static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, HInvoke* invoke) {
   1882   bool can_call = kEmitCompilerReadBarrier &&
   1883       kUseBakerReadBarrier &&
   1884       (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
   1885   LocationSummary* locations = new (arena) LocationSummary(invoke,
   1886                                                            (can_call
   1887                                                                 ? LocationSummary::kCallOnSlowPath
   1888                                                                 : LocationSummary::kNoCall),
   1889                                                            kIntrinsified);
   1890   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
   1891   locations->SetInAt(1, Location::RequiresRegister());
   1892   locations->SetInAt(2, Location::RequiresRegister());
   1893   locations->SetInAt(3, Location::RequiresRegister());
   1894   locations->SetInAt(4, Location::RequiresRegister());
   1895   locations->SetOut(Location::RequiresRegister());
   1896 
   1897   // Temporary register used in CAS by (Baker) read barrier.
   1898   if (can_call) {
   1899     locations->AddTemp(Location::RequiresRegister());
   1900   }
   1901 }
   1902 
   1903 // Note that the caller must supply a properly aligned memory address.
   1904 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
   1905 static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorMIPS* codegen) {
   1906   MipsAssembler* assembler = codegen->GetAssembler();
   1907   LocationSummary* locations = invoke->GetLocations();
   1908   bool isR6 = codegen->GetInstructionSetFeatures().IsR6();
   1909   Register base = locations->InAt(1).AsRegister<Register>();
   1910   Location offset_loc = locations->InAt(2);
   1911   Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
   1912   Register expected = locations->InAt(3).AsRegister<Register>();
   1913   Register value = locations->InAt(4).AsRegister<Register>();
   1914   Location out_loc = locations->Out();
   1915   Register out = out_loc.AsRegister<Register>();
   1916 
   1917   DCHECK_NE(base, out);
   1918   DCHECK_NE(offset_lo, out);
   1919   DCHECK_NE(expected, out);
   1920 
   1921   if (type == Primitive::kPrimNot) {
   1922     // The only read barrier implementation supporting the
   1923     // UnsafeCASObject intrinsic is the Baker-style read barriers.
   1924     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
   1925 
   1926     // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
   1927     // object and scan the receiver at the next GC for nothing.
   1928     bool value_can_be_null = true;  // TODO: Worth finding out this information?
   1929     codegen->MarkGCCard(base, value, value_can_be_null);
   1930 
   1931     if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
   1932       Location temp = locations->GetTemp(0);
   1933       // Need to make sure the reference stored in the field is a to-space
   1934       // one before attempting the CAS or the CAS could fail incorrectly.
   1935       codegen->GenerateReferenceLoadWithBakerReadBarrier(
   1936           invoke,
   1937           out_loc,  // Unused, used only as a "temporary" within the read barrier.
   1938           base,
   1939           /* offset */ 0u,
   1940           /* index */ offset_loc,
   1941           ScaleFactor::TIMES_1,
   1942           temp,
   1943           /* needs_null_check */ false,
   1944           /* always_update_field */ true);
   1945     }
   1946   }
   1947 
   1948   MipsLabel loop_head, exit_loop;
   1949   __ Addu(TMP, base, offset_lo);
   1950 
   1951   if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
   1952     __ PoisonHeapReference(expected);
   1953     // Do not poison `value`, if it is the same register as
   1954     // `expected`, which has just been poisoned.
   1955     if (value != expected) {
   1956       __ PoisonHeapReference(value);
   1957     }
   1958   }
   1959 
   1960   // do {
   1961   //   tmp_value = [tmp_ptr] - expected;
   1962   // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
   1963   // result = tmp_value != 0;
   1964 
   1965   __ Sync(0);
   1966   __ Bind(&loop_head);
   1967   if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
   1968     if (isR6) {
   1969       __ LlR6(out, TMP);
   1970     } else {
   1971       __ LlR2(out, TMP);
   1972     }
   1973   } else {
   1974     LOG(FATAL) << "Unsupported op size " << type;
   1975     UNREACHABLE();
   1976   }
   1977   __ Subu(out, out, expected);          // If we didn't get the 'expected'
   1978   __ Sltiu(out, out, 1);                // value, set 'out' to false, and
   1979   __ Beqz(out, &exit_loop);             // return.
   1980   __ Move(out, value);  // Use 'out' for the 'store conditional' instruction.
   1981                         // If we use 'value' directly, we would lose 'value'
   1982                         // in the case that the store fails.  Whether the
   1983                         // store succeeds, or fails, it will load the
   1984                         // correct Boolean value into the 'out' register.
   1985   // This test isn't really necessary. We only support Primitive::kPrimInt,
   1986   // Primitive::kPrimNot, and we already verified that we're working on one
   1987   // of those two types. It's left here in case the code needs to support
   1988   // other types in the future.
   1989   if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
   1990     if (isR6) {
   1991       __ ScR6(out, TMP);
   1992     } else {
   1993       __ ScR2(out, TMP);
   1994     }
   1995   }
   1996   __ Beqz(out, &loop_head);     // If we couldn't do the read-modify-write
   1997                                 // cycle atomically then retry.
   1998   __ Bind(&exit_loop);
   1999   __ Sync(0);
   2000 
   2001   if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
   2002     __ UnpoisonHeapReference(expected);
   2003     // Do not unpoison `value`, if it is the same register as
   2004     // `expected`, which has just been unpoisoned.
   2005     if (value != expected) {
   2006       __ UnpoisonHeapReference(value);
   2007     }
   2008   }
   2009 }
   2010 
   2011 // boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
   2012 void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
   2013   CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
   2014 }
   2015 
   2016 void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
   2017   GenCas(invoke, Primitive::kPrimInt, codegen_);
   2018 }
   2019 
   2020 // boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
   2021 void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
   2022   // The only read barrier implementation supporting the
   2023   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   2024   if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) {
   2025     return;
   2026   }
   2027 
   2028   CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
   2029 }
   2030 
   2031 void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
   2032   // The only read barrier implementation supporting the
   2033   // UnsafeCASObject intrinsic is the Baker-style read barriers.
   2034   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
   2035 
   2036   GenCas(invoke, Primitive::kPrimNot, codegen_);
   2037 }
   2038 
   2039 // int java.lang.String.compareTo(String anotherString)
   2040 void IntrinsicLocationsBuilderMIPS::VisitStringCompareTo(HInvoke* invoke) {
   2041   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2042                                                             LocationSummary::kCallOnMainAndSlowPath,
   2043                                                             kIntrinsified);
   2044   InvokeRuntimeCallingConvention calling_convention;
   2045   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2046   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2047   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
   2048   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
   2049 }
   2050 
   2051 void IntrinsicCodeGeneratorMIPS::VisitStringCompareTo(HInvoke* invoke) {
   2052   MipsAssembler* assembler = GetAssembler();
   2053   LocationSummary* locations = invoke->GetLocations();
   2054 
   2055   // Note that the null check must have been done earlier.
   2056   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
   2057 
   2058   Register argument = locations->InAt(1).AsRegister<Register>();
   2059   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
   2060   codegen_->AddSlowPath(slow_path);
   2061   __ Beqz(argument, slow_path->GetEntryLabel());
   2062   codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
   2063   __ Bind(slow_path->GetExitLabel());
   2064 }
   2065 
   2066 // boolean java.lang.String.equals(Object anObject)
   2067 void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
   2068   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2069                                                             LocationSummary::kNoCall,
   2070                                                             kIntrinsified);
   2071   locations->SetInAt(0, Location::RequiresRegister());
   2072   locations->SetInAt(1, Location::RequiresRegister());
   2073   locations->SetOut(Location::RequiresRegister());
   2074 
   2075   // Temporary registers to store lengths of strings and for calculations.
   2076   locations->AddTemp(Location::RequiresRegister());
   2077   locations->AddTemp(Location::RequiresRegister());
   2078   locations->AddTemp(Location::RequiresRegister());
   2079 }
   2080 
   2081 void IntrinsicCodeGeneratorMIPS::VisitStringEquals(HInvoke* invoke) {
   2082   MipsAssembler* assembler = GetAssembler();
   2083   LocationSummary* locations = invoke->GetLocations();
   2084 
   2085   Register str = locations->InAt(0).AsRegister<Register>();
   2086   Register arg = locations->InAt(1).AsRegister<Register>();
   2087   Register out = locations->Out().AsRegister<Register>();
   2088 
   2089   Register temp1 = locations->GetTemp(0).AsRegister<Register>();
   2090   Register temp2 = locations->GetTemp(1).AsRegister<Register>();
   2091   Register temp3 = locations->GetTemp(2).AsRegister<Register>();
   2092 
   2093   MipsLabel loop;
   2094   MipsLabel end;
   2095   MipsLabel return_true;
   2096   MipsLabel return_false;
   2097 
   2098   // Get offsets of count, value, and class fields within a string object.
   2099   const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
   2100   const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
   2101   const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
   2102 
   2103   // Note that the null check must have been done earlier.
   2104   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
   2105 
   2106   // If the register containing the pointer to "this", and the register
   2107   // containing the pointer to "anObject" are the same register then
   2108   // "this", and "anObject" are the same object and we can
   2109   // short-circuit the logic to a true result.
   2110   if (str == arg) {
   2111     __ LoadConst32(out, 1);
   2112     return;
   2113   }
   2114   StringEqualsOptimizations optimizations(invoke);
   2115   if (!optimizations.GetArgumentNotNull()) {
   2116     // Check if input is null, return false if it is.
   2117     __ Beqz(arg, &return_false);
   2118   }
   2119 
   2120   // Reference equality check, return true if same reference.
   2121   __ Beq(str, arg, &return_true);
   2122 
   2123   if (!optimizations.GetArgumentIsString()) {
   2124     // Instanceof check for the argument by comparing class fields.
   2125     // All string objects must have the same type since String cannot be subclassed.
   2126     // Receiver must be a string object, so its class field is equal to all strings' class fields.
   2127     // If the argument is a string object, its class field must be equal to receiver's class field.
   2128     __ Lw(temp1, str, class_offset);
   2129     __ Lw(temp2, arg, class_offset);
   2130     __ Bne(temp1, temp2, &return_false);
   2131   }
   2132 
   2133   // Load `count` fields of this and argument strings.
   2134   __ Lw(temp1, str, count_offset);
   2135   __ Lw(temp2, arg, count_offset);
   2136   // Check if `count` fields are equal, return false if they're not.
   2137   // Also compares the compression style, if differs return false.
   2138   __ Bne(temp1, temp2, &return_false);
   2139   // Return true if both strings are empty. Even with string compression `count == 0` means empty.
   2140   static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
   2141                 "Expecting 0=compressed, 1=uncompressed");
   2142   __ Beqz(temp1, &return_true);
   2143 
   2144   // Don't overwrite input registers
   2145   __ Move(TMP, str);
   2146   __ Move(temp3, arg);
   2147 
   2148   // Assertions that must hold in order to compare strings 4 bytes at a time.
   2149   DCHECK_ALIGNED(value_offset, 4);
   2150   static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
   2151 
   2152   // For string compression, calculate the number of bytes to compare (not chars).
   2153   if (mirror::kUseStringCompression) {
   2154     // Extract compression flag.
   2155     if (IsR2OrNewer()) {
   2156       __ Ext(temp2, temp1, 0, 1);
   2157     } else {
   2158       __ Sll(temp2, temp1, 31);
   2159       __ Srl(temp2, temp2, 31);
   2160     }
   2161     __ Srl(temp1, temp1, 1);             // Extract length.
   2162     __ Sllv(temp1, temp1, temp2);        // Double the byte count if uncompressed.
   2163   }
   2164 
   2165   // Loop to compare strings 4 bytes at a time starting at the beginning of the string.
   2166   // Ok to do this because strings are zero-padded to kObjectAlignment.
   2167   __ Bind(&loop);
   2168   __ Lw(out, TMP, value_offset);
   2169   __ Lw(temp2, temp3, value_offset);
   2170   __ Bne(out, temp2, &return_false);
   2171   __ Addiu(TMP, TMP, 4);
   2172   __ Addiu(temp3, temp3, 4);
   2173   // With string compression, we have compared 4 bytes, otherwise 2 chars.
   2174   __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -4 : -2);
   2175   __ Bgtz(temp1, &loop);
   2176 
   2177   // Return true and exit the function.
   2178   // If loop does not result in returning false, we return true.
   2179   __ Bind(&return_true);
   2180   __ LoadConst32(out, 1);
   2181   __ B(&end);
   2182 
   2183   // Return false and exit the function.
   2184   __ Bind(&return_false);
   2185   __ LoadConst32(out, 0);
   2186   __ Bind(&end);
   2187 }
   2188 
   2189 static void GenerateStringIndexOf(HInvoke* invoke,
   2190                                   bool start_at_zero,
   2191                                   MipsAssembler* assembler,
   2192                                   CodeGeneratorMIPS* codegen,
   2193                                   ArenaAllocator* allocator) {
   2194   LocationSummary* locations = invoke->GetLocations();
   2195   Register tmp_reg = start_at_zero ? locations->GetTemp(0).AsRegister<Register>() : TMP;
   2196 
   2197   // Note that the null check must have been done earlier.
   2198   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
   2199 
   2200   // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
   2201   // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
   2202   SlowPathCodeMIPS* slow_path = nullptr;
   2203   HInstruction* code_point = invoke->InputAt(1);
   2204   if (code_point->IsIntConstant()) {
   2205     if (!IsUint<16>(code_point->AsIntConstant()->GetValue())) {
   2206       // Always needs the slow-path. We could directly dispatch to it,
   2207       // but this case should be rare, so for simplicity just put the
   2208       // full slow-path down and branch unconditionally.
   2209       slow_path = new (allocator) IntrinsicSlowPathMIPS(invoke);
   2210       codegen->AddSlowPath(slow_path);
   2211       __ B(slow_path->GetEntryLabel());
   2212       __ Bind(slow_path->GetExitLabel());
   2213       return;
   2214     }
   2215   } else if (code_point->GetType() != Primitive::kPrimChar) {
   2216     Register char_reg = locations->InAt(1).AsRegister<Register>();
   2217     // The "bltu" conditional branch tests to see if the character value
   2218     // fits in a valid 16-bit (MIPS halfword) value. If it doesn't then
   2219     // the character being searched for, if it exists in the string, is
   2220     // encoded using UTF-16 and stored in the string as two (16-bit)
   2221     // halfwords. Currently the assembly code used to implement this
   2222     // intrinsic doesn't support searching for a character stored as
   2223     // two halfwords so we fallback to using the generic implementation
   2224     // of indexOf().
   2225     __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
   2226     slow_path = new (allocator) IntrinsicSlowPathMIPS(invoke);
   2227     codegen->AddSlowPath(slow_path);
   2228     __ Bltu(tmp_reg, char_reg, slow_path->GetEntryLabel());
   2229   }
   2230 
   2231   if (start_at_zero) {
   2232     DCHECK_EQ(tmp_reg, A2);
   2233     // Start-index = 0.
   2234     __ Clear(tmp_reg);
   2235   }
   2236 
   2237   codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
   2238   if (slow_path != nullptr) {
   2239     __ Bind(slow_path->GetExitLabel());
   2240   }
   2241 }
   2242 
   2243 // int java.lang.String.indexOf(int ch)
   2244 void IntrinsicLocationsBuilderMIPS::VisitStringIndexOf(HInvoke* invoke) {
   2245   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2246                                                             LocationSummary::kCallOnMainAndSlowPath,
   2247                                                             kIntrinsified);
   2248   // We have a hand-crafted assembly stub that follows the runtime
   2249   // calling convention. So it's best to align the inputs accordingly.
   2250   InvokeRuntimeCallingConvention calling_convention;
   2251   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2252   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2253   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
   2254   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
   2255 
   2256   // Need a temp for slow-path codepoint compare, and need to send start-index=0.
   2257   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   2258 }
   2259 
   2260 void IntrinsicCodeGeneratorMIPS::VisitStringIndexOf(HInvoke* invoke) {
   2261   GenerateStringIndexOf(invoke,
   2262                         /* start_at_zero */ true,
   2263                         GetAssembler(),
   2264                         codegen_,
   2265                         GetAllocator());
   2266 }
   2267 
   2268 // int java.lang.String.indexOf(int ch, int fromIndex)
   2269 void IntrinsicLocationsBuilderMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
   2270   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2271                                                             LocationSummary::kCallOnMainAndSlowPath,
   2272                                                             kIntrinsified);
   2273   // We have a hand-crafted assembly stub that follows the runtime
   2274   // calling convention. So it's best to align the inputs accordingly.
   2275   InvokeRuntimeCallingConvention calling_convention;
   2276   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2277   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2278   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   2279   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
   2280   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
   2281 
   2282   // Need a temp for slow-path codepoint compare.
   2283   locations->AddTemp(Location::RequiresRegister());
   2284 }
   2285 
   2286 void IntrinsicCodeGeneratorMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
   2287   GenerateStringIndexOf(invoke,
   2288                         /* start_at_zero */ false,
   2289                         GetAssembler(),
   2290                         codegen_,
   2291                         GetAllocator());
   2292 }
   2293 
   2294 // java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
   2295 void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
   2296   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2297                                                             LocationSummary::kCallOnMainAndSlowPath,
   2298                                                             kIntrinsified);
   2299   InvokeRuntimeCallingConvention calling_convention;
   2300   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2301   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2302   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   2303   locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
   2304   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
   2305   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
   2306 }
   2307 
   2308 void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
   2309   MipsAssembler* assembler = GetAssembler();
   2310   LocationSummary* locations = invoke->GetLocations();
   2311 
   2312   Register byte_array = locations->InAt(0).AsRegister<Register>();
   2313   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
   2314   codegen_->AddSlowPath(slow_path);
   2315   __ Beqz(byte_array, slow_path->GetEntryLabel());
   2316   codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
   2317   __ Bind(slow_path->GetExitLabel());
   2318 }
   2319 
   2320 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
   2321 void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
   2322   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2323                                                             LocationSummary::kCallOnMainOnly,
   2324                                                             kIntrinsified);
   2325   InvokeRuntimeCallingConvention calling_convention;
   2326   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2327   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   2328   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   2329   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
   2330   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
   2331 }
   2332 
   2333 void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
   2334   // No need to emit code checking whether `locations->InAt(2)` is a null
   2335   // pointer, as callers of the native method
   2336   //
   2337   //   java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
   2338   //
   2339   // all include a null check on `data` before calling that method.
   2340   codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
   2341 }
   2342 
   2343 // java.lang.StringFactory.newStringFromString(String toCopy)
   2344 void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
   2345   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2346                                                             LocationSummary::kCallOnMainAndSlowPath,
   2347                                                             kIntrinsified);
   2348   InvokeRuntimeCallingConvention calling_convention;
   2349   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
   2350   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
   2351   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
   2352 }
   2353 
   2354 void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
   2355   MipsAssembler* assembler = GetAssembler();
   2356   LocationSummary* locations = invoke->GetLocations();
   2357 
   2358   Register string_to_copy = locations->InAt(0).AsRegister<Register>();
   2359   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
   2360   codegen_->AddSlowPath(slow_path);
   2361   __ Beqz(string_to_copy, slow_path->GetEntryLabel());
   2362   codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc());
   2363   __ Bind(slow_path->GetExitLabel());
   2364 }
   2365 
   2366 static void GenIsInfinite(LocationSummary* locations,
   2367                           const Primitive::Type type,
   2368                           const bool isR6,
   2369                           MipsAssembler* assembler) {
   2370   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
   2371   Register out = locations->Out().AsRegister<Register>();
   2372 
   2373   DCHECK(type == Primitive::kPrimFloat || type == Primitive::kPrimDouble);
   2374 
   2375   if (isR6) {
   2376     if (type == Primitive::kPrimDouble) {
   2377         __ ClassD(FTMP, in);
   2378     } else {
   2379         __ ClassS(FTMP, in);
   2380     }
   2381     __ Mfc1(out, FTMP);
   2382     __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
   2383     __ Sltu(out, ZERO, out);
   2384   } else {
   2385     // If one, or more, of the exponent bits is zero, then the number can't be infinite.
   2386     if (type == Primitive::kPrimDouble) {
   2387       __ MoveFromFpuHigh(TMP, in);
   2388       __ LoadConst32(AT, High32Bits(kPositiveInfinityDouble));
   2389     } else {
   2390       __ Mfc1(TMP, in);
   2391       __ LoadConst32(AT, kPositiveInfinityFloat);
   2392     }
   2393     __ Xor(TMP, TMP, AT);
   2394 
   2395     __ Sll(TMP, TMP, 1);
   2396 
   2397     if (type == Primitive::kPrimDouble) {
   2398       __ Mfc1(AT, in);
   2399       __ Or(TMP, TMP, AT);
   2400     }
   2401     // If any of the significand bits are one, then the number is not infinite.
   2402     __ Sltiu(out, TMP, 1);
   2403   }
   2404 }
   2405 
   2406 // boolean java.lang.Float.isInfinite(float)
   2407 void IntrinsicLocationsBuilderMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
   2408   CreateFPToIntLocations(arena_, invoke);
   2409 }
   2410 
   2411 void IntrinsicCodeGeneratorMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
   2412   GenIsInfinite(invoke->GetLocations(), Primitive::kPrimFloat, IsR6(), GetAssembler());
   2413 }
   2414 
   2415 // boolean java.lang.Double.isInfinite(double)
   2416 void IntrinsicLocationsBuilderMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
   2417   CreateFPToIntLocations(arena_, invoke);
   2418 }
   2419 
   2420 void IntrinsicCodeGeneratorMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
   2421   GenIsInfinite(invoke->GetLocations(), Primitive::kPrimDouble, IsR6(), GetAssembler());
   2422 }
   2423 
   2424 static void GenHighestOneBit(LocationSummary* locations,
   2425                              const Primitive::Type type,
   2426                              bool isR6,
   2427                              MipsAssembler* assembler) {
   2428   DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
   2429 
   2430   if (type == Primitive::kPrimLong) {
   2431     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
   2432     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
   2433     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
   2434     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
   2435 
   2436     if (isR6) {
   2437       __ ClzR6(TMP, in_hi);
   2438     } else {
   2439       __ ClzR2(TMP, in_hi);
   2440     }
   2441     __ LoadConst32(AT, 0x80000000);
   2442     __ Srlv(out_hi, AT, TMP);
   2443     __ And(out_hi, out_hi, in_hi);
   2444     if (isR6) {
   2445       __ ClzR6(TMP, in_lo);
   2446     } else {
   2447       __ ClzR2(TMP, in_lo);
   2448     }
   2449     __ Srlv(out_lo, AT, TMP);
   2450     __ And(out_lo, out_lo, in_lo);
   2451     if (isR6) {
   2452       __ Seleqz(out_lo, out_lo, out_hi);
   2453     } else {
   2454       __ Movn(out_lo, ZERO, out_hi);
   2455     }
   2456   } else {
   2457     Register in = locations->InAt(0).AsRegister<Register>();
   2458     Register out = locations->Out().AsRegister<Register>();
   2459 
   2460     if (isR6) {
   2461       __ ClzR6(TMP, in);
   2462     } else {
   2463       __ ClzR2(TMP, in);
   2464     }
   2465     __ LoadConst32(AT, 0x80000000);
   2466     __ Srlv(AT, AT, TMP);  // Srlv shifts in the range of [0;31] bits (lower 5 bits of arg).
   2467     __ And(out, AT, in);   // So this is required for 0 (=shift by 32).
   2468   }
   2469 }
   2470 
   2471 // int java.lang.Integer.highestOneBit(int)
   2472 void IntrinsicLocationsBuilderMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
   2473   CreateIntToIntLocations(arena_, invoke);
   2474 }
   2475 
   2476 void IntrinsicCodeGeneratorMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
   2477   GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
   2478 }
   2479 
   2480 // long java.lang.Long.highestOneBit(long)
   2481 void IntrinsicLocationsBuilderMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
   2482   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
   2483 }
   2484 
   2485 void IntrinsicCodeGeneratorMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
   2486   GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
   2487 }
   2488 
   2489 static void GenLowestOneBit(LocationSummary* locations,
   2490                             const Primitive::Type type,
   2491                             bool isR6,
   2492                             MipsAssembler* assembler) {
   2493   DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
   2494 
   2495   if (type == Primitive::kPrimLong) {
   2496     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
   2497     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
   2498     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
   2499     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
   2500 
   2501     __ Subu(TMP, ZERO, in_lo);
   2502     __ And(out_lo, TMP, in_lo);
   2503     __ Subu(TMP, ZERO, in_hi);
   2504     __ And(out_hi, TMP, in_hi);
   2505     if (isR6) {
   2506       __ Seleqz(out_hi, out_hi, out_lo);
   2507     } else {
   2508       __ Movn(out_hi, ZERO, out_lo);
   2509     }
   2510   } else {
   2511     Register in = locations->InAt(0).AsRegister<Register>();
   2512     Register out = locations->Out().AsRegister<Register>();
   2513 
   2514     __ Subu(TMP, ZERO, in);
   2515     __ And(out, TMP, in);
   2516   }
   2517 }
   2518 
   2519 // int java.lang.Integer.lowestOneBit(int)
   2520 void IntrinsicLocationsBuilderMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
   2521   CreateIntToIntLocations(arena_, invoke);
   2522 }
   2523 
   2524 void IntrinsicCodeGeneratorMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
   2525   GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
   2526 }
   2527 
   2528 // long java.lang.Long.lowestOneBit(long)
   2529 void IntrinsicLocationsBuilderMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
   2530   CreateIntToIntLocations(arena_, invoke);
   2531 }
   2532 
   2533 void IntrinsicCodeGeneratorMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
   2534   GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
   2535 }
   2536 
   2537 // int java.lang.Math.round(float)
   2538 void IntrinsicLocationsBuilderMIPS::VisitMathRoundFloat(HInvoke* invoke) {
   2539   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2540                                                            LocationSummary::kNoCall,
   2541                                                            kIntrinsified);
   2542   locations->SetInAt(0, Location::RequiresFpuRegister());
   2543   locations->AddTemp(Location::RequiresFpuRegister());
   2544   locations->SetOut(Location::RequiresRegister());
   2545 }
   2546 
   2547 void IntrinsicCodeGeneratorMIPS::VisitMathRoundFloat(HInvoke* invoke) {
   2548   LocationSummary* locations = invoke->GetLocations();
   2549   MipsAssembler* assembler = GetAssembler();
   2550   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
   2551   FRegister half = locations->GetTemp(0).AsFpuRegister<FRegister>();
   2552   Register out = locations->Out().AsRegister<Register>();
   2553 
   2554   MipsLabel done;
   2555   MipsLabel finite;
   2556   MipsLabel add;
   2557 
   2558   // if (in.isNaN) {
   2559   //   return 0;
   2560   // }
   2561   //
   2562   // out = floor.w.s(in);
   2563   //
   2564   // /*
   2565   //  * This "if" statement is only needed for the pre-R6 version of floor.w.s
   2566   //  * which outputs Integer.MAX_VALUE for negative numbers with magnitudes
   2567   //  * too large to fit in a 32-bit integer.
   2568   //  *
   2569   //  * Starting with MIPSR6, which always sets FCSR.NAN2008=1, negative
   2570   //  * numbers which are too large to be represented in a 32-bit signed
   2571   //  * integer will be processed by floor.w.s to output Integer.MIN_VALUE,
   2572   //  * and will no longer be processed by this "if" statement.
   2573   //  */
   2574   // if (out == Integer.MAX_VALUE) {
   2575   //   TMP = (in < 0.0f) ? 1 : 0;
   2576   //   /*
   2577   //    * If TMP is 1, then adding it to out will wrap its value from
   2578   //    * Integer.MAX_VALUE to Integer.MIN_VALUE.
   2579   //    */
   2580   //   return out += TMP;
   2581   // }
   2582   //
   2583   // /*
   2584   //  * For negative values not handled by the previous "if" statement the
   2585   //  * test here will correctly set the value of TMP.
   2586   //  */
   2587   // TMP = ((in - out) >= 0.5f) ? 1 : 0;
   2588   // return out += TMP;
   2589 
   2590   // Test for NaN.
   2591   if (IsR6()) {
   2592     __ CmpUnS(FTMP, in, in);
   2593   } else {
   2594     __ CunS(in, in);
   2595   }
   2596 
   2597   // Return zero for NaN.
   2598   __ Move(out, ZERO);
   2599   if (IsR6()) {
   2600     __ Bc1nez(FTMP, &done);
   2601   } else {
   2602     __ Bc1t(&done);
   2603   }
   2604 
   2605   // out = floor(in);
   2606   __ FloorWS(FTMP, in);
   2607   __ Mfc1(out, FTMP);
   2608 
   2609   if (!IsR6()) {
   2610     __ LoadConst32(TMP, -1);
   2611   }
   2612 
   2613   // TMP = (out = java.lang.Integer.MAX_VALUE) ? -1 : 0;
   2614   __ LoadConst32(AT, std::numeric_limits<int32_t>::max());
   2615   __ Bne(AT, out, &finite);
   2616 
   2617   __ Mtc1(ZERO, FTMP);
   2618   if (IsR6()) {
   2619     __ CmpLtS(FTMP, in, FTMP);
   2620     __ Mfc1(TMP, FTMP);
   2621   } else {
   2622     __ ColtS(in, FTMP);
   2623   }
   2624 
   2625   __ B(&add);
   2626 
   2627   __ Bind(&finite);
   2628 
   2629   // TMP = (0.5f <= (in - out)) ? -1 : 0;
   2630   __ Cvtsw(FTMP, FTMP);  // Convert output of floor.w.s back to "float".
   2631   __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
   2632   __ SubS(FTMP, in, FTMP);
   2633   __ Mtc1(AT, half);
   2634   if (IsR6()) {
   2635     __ CmpLeS(FTMP, half, FTMP);
   2636     __ Mfc1(TMP, FTMP);
   2637   } else {
   2638     __ ColeS(half, FTMP);
   2639   }
   2640 
   2641   __ Bind(&add);
   2642 
   2643   if (!IsR6()) {
   2644     __ Movf(TMP, ZERO);
   2645   }
   2646 
   2647   // Return out -= TMP.
   2648   __ Subu(out, out, TMP);
   2649 
   2650   __ Bind(&done);
   2651 }
   2652 
   2653 // void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
   2654 void IntrinsicLocationsBuilderMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
   2655   LocationSummary* locations = new (arena_) LocationSummary(invoke,
   2656                                                             LocationSummary::kNoCall,
   2657                                                             kIntrinsified);
   2658   locations->SetInAt(0, Location::RequiresRegister());
   2659   locations->SetInAt(1, Location::RequiresRegister());
   2660   locations->SetInAt(2, Location::RequiresRegister());
   2661   locations->SetInAt(3, Location::RequiresRegister());
   2662   locations->SetInAt(4, Location::RequiresRegister());
   2663 
   2664   locations->AddTemp(Location::RequiresRegister());
   2665   locations->AddTemp(Location::RequiresRegister());
   2666   locations->AddTemp(Location::RequiresRegister());
   2667 }
   2668 
   2669 void IntrinsicCodeGeneratorMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
   2670   MipsAssembler* assembler = GetAssembler();
   2671   LocationSummary* locations = invoke->GetLocations();
   2672 
   2673   // Check assumption that sizeof(Char) is 2 (used in scaling below).
   2674   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
   2675   DCHECK_EQ(char_size, 2u);
   2676   const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
   2677 
   2678   Register srcObj = locations->InAt(0).AsRegister<Register>();
   2679   Register srcBegin = locations->InAt(1).AsRegister<Register>();
   2680   Register srcEnd = locations->InAt(2).AsRegister<Register>();
   2681   Register dstObj = locations->InAt(3).AsRegister<Register>();
   2682   Register dstBegin = locations->InAt(4).AsRegister<Register>();
   2683 
   2684   Register dstPtr = locations->GetTemp(0).AsRegister<Register>();
   2685   Register srcPtr = locations->GetTemp(1).AsRegister<Register>();
   2686   Register numChrs = locations->GetTemp(2).AsRegister<Register>();
   2687 
   2688   MipsLabel done;
   2689   MipsLabel loop;
   2690 
   2691   // Location of data in char array buffer.
   2692   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
   2693 
   2694   // Get offset of value field within a string object.
   2695   const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
   2696 
   2697   __ Beq(srcEnd, srcBegin, &done);  // No characters to move.
   2698 
   2699   // Calculate number of characters to be copied.
   2700   __ Subu(numChrs, srcEnd, srcBegin);
   2701 
   2702   // Calculate destination address.
   2703   __ Addiu(dstPtr, dstObj, data_offset);
   2704   __ ShiftAndAdd(dstPtr, dstBegin, dstPtr, char_shift);
   2705 
   2706   if (mirror::kUseStringCompression) {
   2707     MipsLabel uncompressed_copy, compressed_loop;
   2708     const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
   2709     // Load count field and extract compression flag.
   2710     __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset);
   2711     __ Sll(TMP, TMP, 31);
   2712 
   2713     // If string is uncompressed, use uncompressed path.
   2714     __ Bnez(TMP, &uncompressed_copy);
   2715 
   2716     // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
   2717     __ Addu(srcPtr, srcObj, srcBegin);
   2718     __ Bind(&compressed_loop);
   2719     __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset);
   2720     __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0);
   2721     __ Addiu(numChrs, numChrs, -1);
   2722     __ Addiu(srcPtr, srcPtr, 1);
   2723     __ Addiu(dstPtr, dstPtr, 2);
   2724     __ Bnez(numChrs, &compressed_loop);
   2725 
   2726     __ B(&done);
   2727     __ Bind(&uncompressed_copy);
   2728   }
   2729 
   2730   // Calculate source address.
   2731   __ Addiu(srcPtr, srcObj, value_offset);
   2732   __ ShiftAndAdd(srcPtr, srcBegin, srcPtr, char_shift);
   2733 
   2734   __ Bind(&loop);
   2735   __ Lh(AT, srcPtr, 0);
   2736   __ Addiu(numChrs, numChrs, -1);
   2737   __ Addiu(srcPtr, srcPtr, char_size);
   2738   __ Sh(AT, dstPtr, 0);
   2739   __ Addiu(dstPtr, dstPtr, char_size);
   2740   __ Bnez(numChrs, &loop);
   2741 
   2742   __ Bind(&done);
   2743 }
   2744 
   2745 static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
   2746   LocationSummary* locations = new (arena) LocationSummary(invoke,
   2747                                                            LocationSummary::kCallOnMainOnly,
   2748                                                            kIntrinsified);
   2749   InvokeRuntimeCallingConvention calling_convention;
   2750 
   2751   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   2752   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
   2753 }
   2754 
   2755 static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
   2756   LocationSummary* locations = new (arena) LocationSummary(invoke,
   2757                                                            LocationSummary::kCallOnMainOnly,
   2758                                                            kIntrinsified);
   2759   InvokeRuntimeCallingConvention calling_convention;
   2760 
   2761   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
   2762   locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
   2763   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
   2764 }
   2765 
   2766 static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorMIPS* codegen, QuickEntrypointEnum entry) {
   2767   LocationSummary* locations = invoke->GetLocations();
   2768   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
   2769   DCHECK_EQ(in, F12);
   2770   FRegister out = locations->Out().AsFpuRegister<FRegister>();
   2771   DCHECK_EQ(out, F0);
   2772 
   2773   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
   2774 }
   2775 
   2776 static void GenFPFPToFPCall(HInvoke* invoke,
   2777                             CodeGeneratorMIPS* codegen,
   2778                             QuickEntrypointEnum entry) {
   2779   LocationSummary* locations = invoke->GetLocations();
   2780   FRegister in0 = locations->InAt(0).AsFpuRegister<FRegister>();
   2781   DCHECK_EQ(in0, F12);
   2782   FRegister in1 = locations->InAt(1).AsFpuRegister<FRegister>();
   2783   DCHECK_EQ(in1, F14);
   2784   FRegister out = locations->Out().AsFpuRegister<FRegister>();
   2785   DCHECK_EQ(out, F0);
   2786 
   2787   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
   2788 }
   2789 
   2790 // static double java.lang.Math.cos(double a)
   2791 void IntrinsicLocationsBuilderMIPS::VisitMathCos(HInvoke* invoke) {
   2792   CreateFPToFPCallLocations(arena_, invoke);
   2793 }
   2794 
   2795 void IntrinsicCodeGeneratorMIPS::VisitMathCos(HInvoke* invoke) {
   2796   GenFPToFPCall(invoke, codegen_, kQuickCos);
   2797 }
   2798 
   2799 // static double java.lang.Math.sin(double a)
   2800 void IntrinsicLocationsBuilderMIPS::VisitMathSin(HInvoke* invoke) {
   2801   CreateFPToFPCallLocations(arena_, invoke);
   2802 }
   2803 
   2804 void IntrinsicCodeGeneratorMIPS::VisitMathSin(HInvoke* invoke) {
   2805   GenFPToFPCall(invoke, codegen_, kQuickSin);
   2806 }
   2807 
   2808 // static double java.lang.Math.acos(double a)
   2809 void IntrinsicLocationsBuilderMIPS::VisitMathAcos(HInvoke* invoke) {
   2810   CreateFPToFPCallLocations(arena_, invoke);
   2811 }
   2812 
   2813 void IntrinsicCodeGeneratorMIPS::VisitMathAcos(HInvoke* invoke) {
   2814   GenFPToFPCall(invoke, codegen_, kQuickAcos);
   2815 }
   2816 
   2817 // static double java.lang.Math.asin(double a)
   2818 void IntrinsicLocationsBuilderMIPS::VisitMathAsin(HInvoke* invoke) {
   2819   CreateFPToFPCallLocations(arena_, invoke);
   2820 }
   2821 
   2822 void IntrinsicCodeGeneratorMIPS::VisitMathAsin(HInvoke* invoke) {
   2823   GenFPToFPCall(invoke, codegen_, kQuickAsin);
   2824 }
   2825 
   2826 // static double java.lang.Math.atan(double a)
   2827 void IntrinsicLocationsBuilderMIPS::VisitMathAtan(HInvoke* invoke) {
   2828   CreateFPToFPCallLocations(arena_, invoke);
   2829 }
   2830 
   2831 void IntrinsicCodeGeneratorMIPS::VisitMathAtan(HInvoke* invoke) {
   2832   GenFPToFPCall(invoke, codegen_, kQuickAtan);
   2833 }
   2834 
   2835 // static double java.lang.Math.atan2(double y, double x)
   2836 void IntrinsicLocationsBuilderMIPS::VisitMathAtan2(HInvoke* invoke) {
   2837   CreateFPFPToFPCallLocations(arena_, invoke);
   2838 }
   2839 
   2840 void IntrinsicCodeGeneratorMIPS::VisitMathAtan2(HInvoke* invoke) {
   2841   GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
   2842 }
   2843 
   2844 // static double java.lang.Math.cbrt(double a)
   2845 void IntrinsicLocationsBuilderMIPS::VisitMathCbrt(HInvoke* invoke) {
   2846   CreateFPToFPCallLocations(arena_, invoke);
   2847 }
   2848 
   2849 void IntrinsicCodeGeneratorMIPS::VisitMathCbrt(HInvoke* invoke) {
   2850   GenFPToFPCall(invoke, codegen_, kQuickCbrt);
   2851 }
   2852 
   2853 // static double java.lang.Math.cosh(double x)
   2854 void IntrinsicLocationsBuilderMIPS::VisitMathCosh(HInvoke* invoke) {
   2855   CreateFPToFPCallLocations(arena_, invoke);
   2856 }
   2857 
   2858 void IntrinsicCodeGeneratorMIPS::VisitMathCosh(HInvoke* invoke) {
   2859   GenFPToFPCall(invoke, codegen_, kQuickCosh);
   2860 }
   2861 
   2862 // static double java.lang.Math.exp(double a)
   2863 void IntrinsicLocationsBuilderMIPS::VisitMathExp(HInvoke* invoke) {
   2864   CreateFPToFPCallLocations(arena_, invoke);
   2865 }
   2866 
   2867 void IntrinsicCodeGeneratorMIPS::VisitMathExp(HInvoke* invoke) {
   2868   GenFPToFPCall(invoke, codegen_, kQuickExp);
   2869 }
   2870 
   2871 // static double java.lang.Math.expm1(double x)
   2872 void IntrinsicLocationsBuilderMIPS::VisitMathExpm1(HInvoke* invoke) {
   2873   CreateFPToFPCallLocations(arena_, invoke);
   2874 }
   2875 
   2876 void IntrinsicCodeGeneratorMIPS::VisitMathExpm1(HInvoke* invoke) {
   2877   GenFPToFPCall(invoke, codegen_, kQuickExpm1);
   2878 }
   2879 
   2880 // static double java.lang.Math.hypot(double x, double y)
   2881 void IntrinsicLocationsBuilderMIPS::VisitMathHypot(HInvoke* invoke) {
   2882   CreateFPFPToFPCallLocations(arena_, invoke);
   2883 }
   2884 
   2885 void IntrinsicCodeGeneratorMIPS::VisitMathHypot(HInvoke* invoke) {
   2886   GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
   2887 }
   2888 
   2889 // static double java.lang.Math.log(double a)
   2890 void IntrinsicLocationsBuilderMIPS::VisitMathLog(HInvoke* invoke) {
   2891   CreateFPToFPCallLocations(arena_, invoke);
   2892 }
   2893 
   2894 void IntrinsicCodeGeneratorMIPS::VisitMathLog(HInvoke* invoke) {
   2895   GenFPToFPCall(invoke, codegen_, kQuickLog);
   2896 }
   2897 
   2898 // static double java.lang.Math.log10(double x)
   2899 void IntrinsicLocationsBuilderMIPS::VisitMathLog10(HInvoke* invoke) {
   2900   CreateFPToFPCallLocations(arena_, invoke);
   2901 }
   2902 
   2903 void IntrinsicCodeGeneratorMIPS::VisitMathLog10(HInvoke* invoke) {
   2904   GenFPToFPCall(invoke, codegen_, kQuickLog10);
   2905 }
   2906 
   2907 // static double java.lang.Math.nextAfter(double start, double direction)
   2908 void IntrinsicLocationsBuilderMIPS::VisitMathNextAfter(HInvoke* invoke) {
   2909   CreateFPFPToFPCallLocations(arena_, invoke);
   2910 }
   2911 
   2912 void IntrinsicCodeGeneratorMIPS::VisitMathNextAfter(HInvoke* invoke) {
   2913   GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
   2914 }
   2915 
   2916 // static double java.lang.Math.sinh(double x)
   2917 void IntrinsicLocationsBuilderMIPS::VisitMathSinh(HInvoke* invoke) {
   2918   CreateFPToFPCallLocations(arena_, invoke);
   2919 }
   2920 
   2921 void IntrinsicCodeGeneratorMIPS::VisitMathSinh(HInvoke* invoke) {
   2922   GenFPToFPCall(invoke, codegen_, kQuickSinh);
   2923 }
   2924 
   2925 // static double java.lang.Math.tan(double a)
   2926 void IntrinsicLocationsBuilderMIPS::VisitMathTan(HInvoke* invoke) {
   2927   CreateFPToFPCallLocations(arena_, invoke);
   2928 }
   2929 
   2930 void IntrinsicCodeGeneratorMIPS::VisitMathTan(HInvoke* invoke) {
   2931   GenFPToFPCall(invoke, codegen_, kQuickTan);
   2932 }
   2933 
   2934 // static double java.lang.Math.tanh(double x)
   2935 void IntrinsicLocationsBuilderMIPS::VisitMathTanh(HInvoke* invoke) {
   2936   CreateFPToFPCallLocations(arena_, invoke);
   2937 }
   2938 
   2939 void IntrinsicCodeGeneratorMIPS::VisitMathTanh(HInvoke* invoke) {
   2940   GenFPToFPCall(invoke, codegen_, kQuickTanh);
   2941 }
   2942 
   2943 // static void java.lang.System.arraycopy(Object src, int srcPos,
   2944 //                                        Object dest, int destPos,
   2945 //                                        int length)
   2946 void IntrinsicLocationsBuilderMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
   2947   HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
   2948   HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
   2949   HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
   2950 
   2951   // As long as we are checking, we might as well check to see if the src and dest
   2952   // positions are >= 0.
   2953   if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
   2954       (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
   2955     // We will have to fail anyways.
   2956     return;
   2957   }
   2958 
   2959   // And since we are already checking, check the length too.
   2960   if (length != nullptr) {
   2961     int32_t len = length->GetValue();
   2962     if (len < 0) {
   2963       // Just call as normal.
   2964       return;
   2965     }
   2966   }
   2967 
   2968   // Okay, it is safe to generate inline code.
   2969   LocationSummary* locations =
   2970       new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
   2971   // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
   2972   locations->SetInAt(0, Location::RequiresRegister());
   2973   locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
   2974   locations->SetInAt(2, Location::RequiresRegister());
   2975   locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
   2976   locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
   2977 
   2978   locations->AddTemp(Location::RequiresRegister());
   2979   locations->AddTemp(Location::RequiresRegister());
   2980   locations->AddTemp(Location::RequiresRegister());
   2981 }
   2982 
   2983 // Utility routine to verify that "length(input) - pos >= length"
   2984 static void EnoughItems(MipsAssembler* assembler,
   2985                         Register length_input_minus_pos,
   2986                         Location length,
   2987                         SlowPathCodeMIPS* slow_path) {
   2988   if (length.IsConstant()) {
   2989     int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
   2990 
   2991     if (IsInt<16>(length_constant)) {
   2992       __ Slti(TMP, length_input_minus_pos, length_constant);
   2993       __ Bnez(TMP, slow_path->GetEntryLabel());
   2994     } else {
   2995       __ LoadConst32(TMP, length_constant);
   2996       __ Blt(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
   2997     }
   2998   } else {
   2999     __ Blt(length_input_minus_pos, length.AsRegister<Register>(), slow_path->GetEntryLabel());
   3000   }
   3001 }
   3002 
   3003 static void CheckPosition(MipsAssembler* assembler,
   3004                           Location pos,
   3005                           Register input,
   3006                           Location length,
   3007                           SlowPathCodeMIPS* slow_path,
   3008                           bool length_is_input_length = false) {
   3009   // Where is the length in the Array?
   3010   const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
   3011 
   3012   // Calculate length(input) - pos.
   3013   if (pos.IsConstant()) {
   3014     int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
   3015     if (pos_const == 0) {
   3016       if (!length_is_input_length) {
   3017         // Check that length(input) >= length.
   3018         __ LoadFromOffset(kLoadWord, AT, input, length_offset);
   3019         EnoughItems(assembler, AT, length, slow_path);
   3020       }
   3021     } else {
   3022       // Check that (length(input) - pos) >= zero.
   3023       __ LoadFromOffset(kLoadWord, AT, input, length_offset);
   3024       DCHECK_GT(pos_const, 0);
   3025       __ Addiu32(AT, AT, -pos_const, TMP);
   3026       __ Bltz(AT, slow_path->GetEntryLabel());
   3027 
   3028       // Verify that (length(input) - pos) >= length.
   3029       EnoughItems(assembler, AT, length, slow_path);
   3030     }
   3031   } else if (length_is_input_length) {
   3032     // The only way the copy can succeed is if pos is zero.
   3033     Register pos_reg = pos.AsRegister<Register>();
   3034     __ Bnez(pos_reg, slow_path->GetEntryLabel());
   3035   } else {
   3036     // Verify that pos >= 0.
   3037     Register pos_reg = pos.AsRegister<Register>();
   3038     __ Bltz(pos_reg, slow_path->GetEntryLabel());
   3039 
   3040     // Check that (length(input) - pos) >= zero.
   3041     __ LoadFromOffset(kLoadWord, AT, input, length_offset);
   3042     __ Subu(AT, AT, pos_reg);
   3043     __ Bltz(AT, slow_path->GetEntryLabel());
   3044 
   3045     // Verify that (length(input) - pos) >= length.
   3046     EnoughItems(assembler, AT, length, slow_path);
   3047   }
   3048 }
   3049 
   3050 void IntrinsicCodeGeneratorMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
   3051   MipsAssembler* assembler = GetAssembler();
   3052   LocationSummary* locations = invoke->GetLocations();
   3053 
   3054   Register src = locations->InAt(0).AsRegister<Register>();
   3055   Location src_pos = locations->InAt(1);
   3056   Register dest = locations->InAt(2).AsRegister<Register>();
   3057   Location dest_pos = locations->InAt(3);
   3058   Location length = locations->InAt(4);
   3059 
   3060   MipsLabel loop;
   3061 
   3062   Register dest_base = locations->GetTemp(0).AsRegister<Register>();
   3063   Register src_base = locations->GetTemp(1).AsRegister<Register>();
   3064   Register count = locations->GetTemp(2).AsRegister<Register>();
   3065 
   3066   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
   3067   codegen_->AddSlowPath(slow_path);
   3068 
   3069   // Bail out if the source and destination are the same (to handle overlap).
   3070   __ Beq(src, dest, slow_path->GetEntryLabel());
   3071 
   3072   // Bail out if the source is null.
   3073   __ Beqz(src, slow_path->GetEntryLabel());
   3074 
   3075   // Bail out if the destination is null.
   3076   __ Beqz(dest, slow_path->GetEntryLabel());
   3077 
   3078   // Load length into register for count.
   3079   if (length.IsConstant()) {
   3080     __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
   3081   } else {
   3082     // If the length is negative, bail out.
   3083     // We have already checked in the LocationsBuilder for the constant case.
   3084     __ Bltz(length.AsRegister<Register>(), slow_path->GetEntryLabel());
   3085 
   3086     __ Move(count, length.AsRegister<Register>());
   3087   }
   3088 
   3089   // Validity checks: source.
   3090   CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
   3091 
   3092   // Validity checks: dest.
   3093   CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
   3094 
   3095   // If count is zero, we're done.
   3096   __ Beqz(count, slow_path->GetExitLabel());
   3097 
   3098   // Okay, everything checks out.  Finally time to do the copy.
   3099   // Check assumption that sizeof(Char) is 2 (used in scaling below).
   3100   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
   3101   DCHECK_EQ(char_size, 2u);
   3102 
   3103   const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
   3104 
   3105   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
   3106 
   3107   // Calculate source and destination addresses.
   3108   if (src_pos.IsConstant()) {
   3109     int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
   3110 
   3111     __ Addiu32(src_base, src, data_offset + char_size * src_pos_const, TMP);
   3112   } else {
   3113     __ Addiu32(src_base, src, data_offset, TMP);
   3114     __ ShiftAndAdd(src_base, src_pos.AsRegister<Register>(), src_base, char_shift);
   3115   }
   3116   if (dest_pos.IsConstant()) {
   3117     int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
   3118 
   3119     __ Addiu32(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
   3120   } else {
   3121     __ Addiu32(dest_base, dest, data_offset, TMP);
   3122     __ ShiftAndAdd(dest_base, dest_pos.AsRegister<Register>(), dest_base, char_shift);
   3123   }
   3124 
   3125   __ Bind(&loop);
   3126   __ Lh(TMP, src_base, 0);
   3127   __ Addiu(src_base, src_base, char_size);
   3128   __ Addiu(count, count, -1);
   3129   __ Sh(TMP, dest_base, 0);
   3130   __ Addiu(dest_base, dest_base, char_size);
   3131   __ Bnez(count, &loop);
   3132 
   3133   __ Bind(slow_path->GetExitLabel());
   3134 }
   3135 
   3136 // Unimplemented intrinsics.
   3137 
   3138 UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
   3139 UNIMPLEMENTED_INTRINSIC(MIPS, MathFloor)
   3140 UNIMPLEMENTED_INTRINSIC(MIPS, MathRint)
   3141 UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundDouble)
   3142 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetLongVolatile);
   3143 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafePutLongVolatile);
   3144 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
   3145 
   3146 UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
   3147 UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
   3148 
   3149 UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
   3150 UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
   3151 UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend);
   3152 UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferLength);
   3153 UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferToString);
   3154 UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderAppend);
   3155 UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderLength);
   3156 UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderToString);
   3157 
   3158 // 1.8.
   3159 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddInt)
   3160 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddLong)
   3161 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetInt)
   3162 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetLong)
   3163 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetObject)
   3164 
   3165 UNIMPLEMENTED_INTRINSIC(MIPS, IntegerValueOf)
   3166 
   3167 UNREACHABLE_INTRINSICS(MIPS)
   3168 
   3169 #undef __
   3170 
   3171 }  // namespace mips
   3172 }  // namespace art
   3173