Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "code_generator_mips64.h"
     18 #include "mirror/array-inl.h"
     19 
     20 namespace art {
     21 namespace mips64 {
     22 
     23 // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
     24 #define __ down_cast<Mips64Assembler*>(GetAssembler())->  // NOLINT
     25 
     26 VectorRegister VectorRegisterFrom(Location location) {
     27   DCHECK(location.IsFpuRegister());
     28   return static_cast<VectorRegister>(location.AsFpuRegister<FpuRegister>());
     29 }
     30 
     31 void LocationsBuilderMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
     32   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
     33   switch (instruction->GetPackedType()) {
     34     case Primitive::kPrimBoolean:
     35     case Primitive::kPrimByte:
     36     case Primitive::kPrimChar:
     37     case Primitive::kPrimShort:
     38     case Primitive::kPrimInt:
     39     case Primitive::kPrimLong:
     40       locations->SetInAt(0, Location::RequiresRegister());
     41       locations->SetOut(Location::RequiresFpuRegister());
     42       break;
     43     case Primitive::kPrimFloat:
     44     case Primitive::kPrimDouble:
     45       locations->SetInAt(0, Location::RequiresFpuRegister());
     46       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
     47       break;
     48     default:
     49       LOG(FATAL) << "Unsupported SIMD type";
     50       UNREACHABLE();
     51   }
     52 }
     53 
     54 void InstructionCodeGeneratorMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
     55   LocationSummary* locations = instruction->GetLocations();
     56   VectorRegister dst = VectorRegisterFrom(locations->Out());
     57   switch (instruction->GetPackedType()) {
     58     case Primitive::kPrimBoolean:
     59     case Primitive::kPrimByte:
     60       DCHECK_EQ(16u, instruction->GetVectorLength());
     61       __ FillB(dst, locations->InAt(0).AsRegister<GpuRegister>());
     62       break;
     63     case Primitive::kPrimChar:
     64     case Primitive::kPrimShort:
     65       DCHECK_EQ(8u, instruction->GetVectorLength());
     66       __ FillH(dst, locations->InAt(0).AsRegister<GpuRegister>());
     67       break;
     68     case Primitive::kPrimInt:
     69       DCHECK_EQ(4u, instruction->GetVectorLength());
     70       __ FillW(dst, locations->InAt(0).AsRegister<GpuRegister>());
     71       break;
     72     case Primitive::kPrimLong:
     73       DCHECK_EQ(2u, instruction->GetVectorLength());
     74       __ FillD(dst, locations->InAt(0).AsRegister<GpuRegister>());
     75       break;
     76     case Primitive::kPrimFloat:
     77       DCHECK_EQ(4u, instruction->GetVectorLength());
     78       __ ReplicateFPToVectorRegister(dst,
     79                                      locations->InAt(0).AsFpuRegister<FpuRegister>(),
     80                                      /* is_double */ false);
     81       break;
     82     case Primitive::kPrimDouble:
     83       DCHECK_EQ(2u, instruction->GetVectorLength());
     84       __ ReplicateFPToVectorRegister(dst,
     85                                      locations->InAt(0).AsFpuRegister<FpuRegister>(),
     86                                      /* is_double */ true);
     87       break;
     88     default:
     89       LOG(FATAL) << "Unsupported SIMD type";
     90       UNREACHABLE();
     91   }
     92 }
     93 
     94 void LocationsBuilderMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) {
     95   LOG(FATAL) << "No SIMD for " << instruction->GetId();
     96 }
     97 
     98 void InstructionCodeGeneratorMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) {
     99   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    100 }
    101 
    102 void LocationsBuilderMIPS64::VisitVecSumReduce(HVecSumReduce* instruction) {
    103   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    104 }
    105 
    106 void InstructionCodeGeneratorMIPS64::VisitVecSumReduce(HVecSumReduce* instruction) {
    107   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    108 }
    109 
    110 // Helper to set up locations for vector unary operations.
    111 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
    112   LocationSummary* locations = new (arena) LocationSummary(instruction);
    113   switch (instruction->GetPackedType()) {
    114     case Primitive::kPrimBoolean:
    115       locations->SetInAt(0, Location::RequiresFpuRegister());
    116       locations->SetOut(Location::RequiresFpuRegister(),
    117                         instruction->IsVecNot() ? Location::kOutputOverlap
    118                                                 : Location::kNoOutputOverlap);
    119       break;
    120     case Primitive::kPrimByte:
    121     case Primitive::kPrimChar:
    122     case Primitive::kPrimShort:
    123     case Primitive::kPrimInt:
    124     case Primitive::kPrimLong:
    125     case Primitive::kPrimFloat:
    126     case Primitive::kPrimDouble:
    127       locations->SetInAt(0, Location::RequiresFpuRegister());
    128       locations->SetOut(Location::RequiresFpuRegister(),
    129                         (instruction->IsVecNeg() || instruction->IsVecAbs())
    130                             ? Location::kOutputOverlap
    131                             : Location::kNoOutputOverlap);
    132       break;
    133     default:
    134       LOG(FATAL) << "Unsupported SIMD type";
    135       UNREACHABLE();
    136   }
    137 }
    138 
    139 void LocationsBuilderMIPS64::VisitVecCnv(HVecCnv* instruction) {
    140   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    141 }
    142 
    143 void InstructionCodeGeneratorMIPS64::VisitVecCnv(HVecCnv* instruction) {
    144   LocationSummary* locations = instruction->GetLocations();
    145   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    146   VectorRegister dst = VectorRegisterFrom(locations->Out());
    147   Primitive::Type from = instruction->GetInputType();
    148   Primitive::Type to = instruction->GetResultType();
    149   if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
    150     DCHECK_EQ(4u, instruction->GetVectorLength());
    151     __ Ffint_sW(dst, src);
    152   } else {
    153     LOG(FATAL) << "Unsupported SIMD type";
    154     UNREACHABLE();
    155   }
    156 }
    157 
    158 void LocationsBuilderMIPS64::VisitVecNeg(HVecNeg* instruction) {
    159   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    160 }
    161 
    162 void InstructionCodeGeneratorMIPS64::VisitVecNeg(HVecNeg* instruction) {
    163   LocationSummary* locations = instruction->GetLocations();
    164   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    165   VectorRegister dst = VectorRegisterFrom(locations->Out());
    166   switch (instruction->GetPackedType()) {
    167     case Primitive::kPrimByte:
    168       DCHECK_EQ(16u, instruction->GetVectorLength());
    169       __ FillB(dst, ZERO);
    170       __ SubvB(dst, dst, src);
    171       break;
    172     case Primitive::kPrimChar:
    173     case Primitive::kPrimShort:
    174       DCHECK_EQ(8u, instruction->GetVectorLength());
    175       __ FillH(dst, ZERO);
    176       __ SubvH(dst, dst, src);
    177       break;
    178     case Primitive::kPrimInt:
    179       DCHECK_EQ(4u, instruction->GetVectorLength());
    180       __ FillW(dst, ZERO);
    181       __ SubvW(dst, dst, src);
    182       break;
    183     case Primitive::kPrimLong:
    184       DCHECK_EQ(2u, instruction->GetVectorLength());
    185       __ FillD(dst, ZERO);
    186       __ SubvD(dst, dst, src);
    187       break;
    188     case Primitive::kPrimFloat:
    189       DCHECK_EQ(4u, instruction->GetVectorLength());
    190       __ FillW(dst, ZERO);
    191       __ FsubW(dst, dst, src);
    192       break;
    193     case Primitive::kPrimDouble:
    194       DCHECK_EQ(2u, instruction->GetVectorLength());
    195       __ FillD(dst, ZERO);
    196       __ FsubD(dst, dst, src);
    197       break;
    198     default:
    199       LOG(FATAL) << "Unsupported SIMD type";
    200       UNREACHABLE();
    201   }
    202 }
    203 
    204 void LocationsBuilderMIPS64::VisitVecAbs(HVecAbs* instruction) {
    205   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    206 }
    207 
    208 void InstructionCodeGeneratorMIPS64::VisitVecAbs(HVecAbs* instruction) {
    209   LocationSummary* locations = instruction->GetLocations();
    210   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    211   VectorRegister dst = VectorRegisterFrom(locations->Out());
    212   switch (instruction->GetPackedType()) {
    213     case Primitive::kPrimByte:
    214       DCHECK_EQ(16u, instruction->GetVectorLength());
    215       __ FillB(dst, ZERO);       // all zeroes
    216       __ Add_aB(dst, dst, src);  // dst = abs(0) + abs(src)
    217       break;
    218     case Primitive::kPrimChar:
    219     case Primitive::kPrimShort:
    220       DCHECK_EQ(8u, instruction->GetVectorLength());
    221       __ FillH(dst, ZERO);       // all zeroes
    222       __ Add_aH(dst, dst, src);  // dst = abs(0) + abs(src)
    223       break;
    224     case Primitive::kPrimInt:
    225       DCHECK_EQ(4u, instruction->GetVectorLength());
    226       __ FillW(dst, ZERO);       // all zeroes
    227       __ Add_aW(dst, dst, src);  // dst = abs(0) + abs(src)
    228       break;
    229     case Primitive::kPrimLong:
    230       DCHECK_EQ(2u, instruction->GetVectorLength());
    231       __ FillD(dst, ZERO);       // all zeroes
    232       __ Add_aD(dst, dst, src);  // dst = abs(0) + abs(src)
    233       break;
    234     case Primitive::kPrimFloat:
    235       DCHECK_EQ(4u, instruction->GetVectorLength());
    236       __ LdiW(dst, -1);          // all ones
    237       __ SrliW(dst, dst, 1);
    238       __ AndV(dst, dst, src);
    239       break;
    240     case Primitive::kPrimDouble:
    241       DCHECK_EQ(2u, instruction->GetVectorLength());
    242       __ LdiD(dst, -1);          // all ones
    243       __ SrliD(dst, dst, 1);
    244       __ AndV(dst, dst, src);
    245       break;
    246     default:
    247       LOG(FATAL) << "Unsupported SIMD type";
    248       UNREACHABLE();
    249   }
    250 }
    251 
    252 void LocationsBuilderMIPS64::VisitVecNot(HVecNot* instruction) {
    253   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    254 }
    255 
    256 void InstructionCodeGeneratorMIPS64::VisitVecNot(HVecNot* instruction) {
    257   LocationSummary* locations = instruction->GetLocations();
    258   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    259   VectorRegister dst = VectorRegisterFrom(locations->Out());
    260   switch (instruction->GetPackedType()) {
    261     case Primitive::kPrimBoolean:  // special case boolean-not
    262       DCHECK_EQ(16u, instruction->GetVectorLength());
    263       __ LdiB(dst, 1);
    264       __ XorV(dst, dst, src);
    265       break;
    266     case Primitive::kPrimByte:
    267     case Primitive::kPrimChar:
    268     case Primitive::kPrimShort:
    269     case Primitive::kPrimInt:
    270     case Primitive::kPrimLong:
    271     case Primitive::kPrimFloat:
    272     case Primitive::kPrimDouble:
    273       DCHECK_LE(2u, instruction->GetVectorLength());
    274       DCHECK_LE(instruction->GetVectorLength(), 16u);
    275       __ NorV(dst, src, src);  // lanes do not matter
    276       break;
    277     default:
    278       LOG(FATAL) << "Unsupported SIMD type";
    279       UNREACHABLE();
    280   }
    281 }
    282 
    283 // Helper to set up locations for vector binary operations.
    284 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
    285   LocationSummary* locations = new (arena) LocationSummary(instruction);
    286   switch (instruction->GetPackedType()) {
    287     case Primitive::kPrimBoolean:
    288     case Primitive::kPrimByte:
    289     case Primitive::kPrimChar:
    290     case Primitive::kPrimShort:
    291     case Primitive::kPrimInt:
    292     case Primitive::kPrimLong:
    293     case Primitive::kPrimFloat:
    294     case Primitive::kPrimDouble:
    295       locations->SetInAt(0, Location::RequiresFpuRegister());
    296       locations->SetInAt(1, Location::RequiresFpuRegister());
    297       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    298       break;
    299     default:
    300       LOG(FATAL) << "Unsupported SIMD type";
    301       UNREACHABLE();
    302   }
    303 }
    304 
    305 void LocationsBuilderMIPS64::VisitVecAdd(HVecAdd* instruction) {
    306   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    307 }
    308 
    309 void InstructionCodeGeneratorMIPS64::VisitVecAdd(HVecAdd* instruction) {
    310   LocationSummary* locations = instruction->GetLocations();
    311   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    312   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    313   VectorRegister dst = VectorRegisterFrom(locations->Out());
    314   switch (instruction->GetPackedType()) {
    315     case Primitive::kPrimByte:
    316       DCHECK_EQ(16u, instruction->GetVectorLength());
    317       __ AddvB(dst, lhs, rhs);
    318       break;
    319     case Primitive::kPrimChar:
    320     case Primitive::kPrimShort:
    321       DCHECK_EQ(8u, instruction->GetVectorLength());
    322       __ AddvH(dst, lhs, rhs);
    323       break;
    324     case Primitive::kPrimInt:
    325       DCHECK_EQ(4u, instruction->GetVectorLength());
    326       __ AddvW(dst, lhs, rhs);
    327       break;
    328     case Primitive::kPrimLong:
    329       DCHECK_EQ(2u, instruction->GetVectorLength());
    330       __ AddvD(dst, lhs, rhs);
    331       break;
    332     case Primitive::kPrimFloat:
    333       DCHECK_EQ(4u, instruction->GetVectorLength());
    334       __ FaddW(dst, lhs, rhs);
    335       break;
    336     case Primitive::kPrimDouble:
    337       DCHECK_EQ(2u, instruction->GetVectorLength());
    338       __ FaddD(dst, lhs, rhs);
    339       break;
    340     default:
    341       LOG(FATAL) << "Unsupported SIMD type";
    342       UNREACHABLE();
    343   }
    344 }
    345 
    346 void LocationsBuilderMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    347   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    348 }
    349 
    350 void InstructionCodeGeneratorMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    351   LocationSummary* locations = instruction->GetLocations();
    352   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    353   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    354   VectorRegister dst = VectorRegisterFrom(locations->Out());
    355   switch (instruction->GetPackedType()) {
    356     case Primitive::kPrimByte:
    357       DCHECK_EQ(16u, instruction->GetVectorLength());
    358       if (instruction->IsUnsigned()) {
    359         instruction->IsRounded()
    360             ? __ Aver_uB(dst, lhs, rhs)
    361             : __ Ave_uB(dst, lhs, rhs);
    362       } else {
    363         instruction->IsRounded()
    364             ? __ Aver_sB(dst, lhs, rhs)
    365             : __ Ave_sB(dst, lhs, rhs);
    366       }
    367       break;
    368     case Primitive::kPrimChar:
    369     case Primitive::kPrimShort:
    370       DCHECK_EQ(8u, instruction->GetVectorLength());
    371       if (instruction->IsUnsigned()) {
    372         instruction->IsRounded()
    373             ? __ Aver_uH(dst, lhs, rhs)
    374             : __ Ave_uH(dst, lhs, rhs);
    375       } else {
    376         instruction->IsRounded()
    377             ? __ Aver_sH(dst, lhs, rhs)
    378             : __ Ave_sH(dst, lhs, rhs);
    379       }
    380       break;
    381     default:
    382       LOG(FATAL) << "Unsupported SIMD type";
    383       UNREACHABLE();
    384   }
    385 }
    386 
    387 void LocationsBuilderMIPS64::VisitVecSub(HVecSub* instruction) {
    388   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    389 }
    390 
    391 void InstructionCodeGeneratorMIPS64::VisitVecSub(HVecSub* instruction) {
    392   LocationSummary* locations = instruction->GetLocations();
    393   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    394   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    395   VectorRegister dst = VectorRegisterFrom(locations->Out());
    396   switch (instruction->GetPackedType()) {
    397     case Primitive::kPrimByte:
    398       DCHECK_EQ(16u, instruction->GetVectorLength());
    399       __ SubvB(dst, lhs, rhs);
    400       break;
    401     case Primitive::kPrimChar:
    402     case Primitive::kPrimShort:
    403       DCHECK_EQ(8u, instruction->GetVectorLength());
    404       __ SubvH(dst, lhs, rhs);
    405       break;
    406     case Primitive::kPrimInt:
    407       DCHECK_EQ(4u, instruction->GetVectorLength());
    408       __ SubvW(dst, lhs, rhs);
    409       break;
    410     case Primitive::kPrimLong:
    411       DCHECK_EQ(2u, instruction->GetVectorLength());
    412       __ SubvD(dst, lhs, rhs);
    413       break;
    414     case Primitive::kPrimFloat:
    415       DCHECK_EQ(4u, instruction->GetVectorLength());
    416       __ FsubW(dst, lhs, rhs);
    417       break;
    418     case Primitive::kPrimDouble:
    419       DCHECK_EQ(2u, instruction->GetVectorLength());
    420       __ FsubD(dst, lhs, rhs);
    421       break;
    422     default:
    423       LOG(FATAL) << "Unsupported SIMD type";
    424       UNREACHABLE();
    425   }
    426 }
    427 
    428 void LocationsBuilderMIPS64::VisitVecMul(HVecMul* instruction) {
    429   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    430 }
    431 
    432 void InstructionCodeGeneratorMIPS64::VisitVecMul(HVecMul* instruction) {
    433   LocationSummary* locations = instruction->GetLocations();
    434   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    435   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    436   VectorRegister dst = VectorRegisterFrom(locations->Out());
    437   switch (instruction->GetPackedType()) {
    438     case Primitive::kPrimByte:
    439       DCHECK_EQ(16u, instruction->GetVectorLength());
    440       __ MulvB(dst, lhs, rhs);
    441       break;
    442     case Primitive::kPrimChar:
    443     case Primitive::kPrimShort:
    444       DCHECK_EQ(8u, instruction->GetVectorLength());
    445       __ MulvH(dst, lhs, rhs);
    446       break;
    447     case Primitive::kPrimInt:
    448       DCHECK_EQ(4u, instruction->GetVectorLength());
    449       __ MulvW(dst, lhs, rhs);
    450       break;
    451     case Primitive::kPrimLong:
    452       DCHECK_EQ(2u, instruction->GetVectorLength());
    453       __ MulvD(dst, lhs, rhs);
    454       break;
    455     case Primitive::kPrimFloat:
    456       DCHECK_EQ(4u, instruction->GetVectorLength());
    457       __ FmulW(dst, lhs, rhs);
    458       break;
    459     case Primitive::kPrimDouble:
    460       DCHECK_EQ(2u, instruction->GetVectorLength());
    461       __ FmulD(dst, lhs, rhs);
    462       break;
    463     default:
    464       LOG(FATAL) << "Unsupported SIMD type";
    465       UNREACHABLE();
    466   }
    467 }
    468 
    469 void LocationsBuilderMIPS64::VisitVecDiv(HVecDiv* instruction) {
    470   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    471 }
    472 
    473 void InstructionCodeGeneratorMIPS64::VisitVecDiv(HVecDiv* instruction) {
    474   LocationSummary* locations = instruction->GetLocations();
    475   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    476   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    477   VectorRegister dst = VectorRegisterFrom(locations->Out());
    478   switch (instruction->GetPackedType()) {
    479     case Primitive::kPrimFloat:
    480       DCHECK_EQ(4u, instruction->GetVectorLength());
    481       __ FdivW(dst, lhs, rhs);
    482       break;
    483     case Primitive::kPrimDouble:
    484       DCHECK_EQ(2u, instruction->GetVectorLength());
    485       __ FdivD(dst, lhs, rhs);
    486       break;
    487     default:
    488       LOG(FATAL) << "Unsupported SIMD type";
    489       UNREACHABLE();
    490   }
    491 }
    492 
    493 void LocationsBuilderMIPS64::VisitVecMin(HVecMin* instruction) {
    494   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    495 }
    496 
    497 void InstructionCodeGeneratorMIPS64::VisitVecMin(HVecMin* instruction) {
    498   LocationSummary* locations = instruction->GetLocations();
    499   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    500   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    501   VectorRegister dst = VectorRegisterFrom(locations->Out());
    502   switch (instruction->GetPackedType()) {
    503     case Primitive::kPrimByte:
    504       DCHECK_EQ(16u, instruction->GetVectorLength());
    505       if (instruction->IsUnsigned()) {
    506         __ Min_uB(dst, lhs, rhs);
    507       } else {
    508         __ Min_sB(dst, lhs, rhs);
    509       }
    510       break;
    511     case Primitive::kPrimChar:
    512     case Primitive::kPrimShort:
    513       DCHECK_EQ(8u, instruction->GetVectorLength());
    514       if (instruction->IsUnsigned()) {
    515         __ Min_uH(dst, lhs, rhs);
    516       } else {
    517         __ Min_sH(dst, lhs, rhs);
    518       }
    519       break;
    520     case Primitive::kPrimInt:
    521       DCHECK_EQ(4u, instruction->GetVectorLength());
    522       if (instruction->IsUnsigned()) {
    523         __ Min_uW(dst, lhs, rhs);
    524       } else {
    525         __ Min_sW(dst, lhs, rhs);
    526       }
    527       break;
    528     case Primitive::kPrimLong:
    529       DCHECK_EQ(2u, instruction->GetVectorLength());
    530       if (instruction->IsUnsigned()) {
    531         __ Min_uD(dst, lhs, rhs);
    532       } else {
    533         __ Min_sD(dst, lhs, rhs);
    534       }
    535       break;
    536     // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
    537     // TODO: Fix min(x, NaN) cases for float and double.
    538     case Primitive::kPrimFloat:
    539       DCHECK_EQ(4u, instruction->GetVectorLength());
    540       DCHECK(!instruction->IsUnsigned());
    541       __ FminW(dst, lhs, rhs);
    542       break;
    543     case Primitive::kPrimDouble:
    544       DCHECK_EQ(2u, instruction->GetVectorLength());
    545       DCHECK(!instruction->IsUnsigned());
    546       __ FminD(dst, lhs, rhs);
    547       break;
    548     default:
    549       LOG(FATAL) << "Unsupported SIMD type";
    550       UNREACHABLE();
    551   }
    552 }
    553 
    554 void LocationsBuilderMIPS64::VisitVecMax(HVecMax* instruction) {
    555   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    556 }
    557 
    558 void InstructionCodeGeneratorMIPS64::VisitVecMax(HVecMax* instruction) {
    559   LocationSummary* locations = instruction->GetLocations();
    560   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    561   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    562   VectorRegister dst = VectorRegisterFrom(locations->Out());
    563   switch (instruction->GetPackedType()) {
    564     case Primitive::kPrimByte:
    565       DCHECK_EQ(16u, instruction->GetVectorLength());
    566       if (instruction->IsUnsigned()) {
    567         __ Max_uB(dst, lhs, rhs);
    568       } else {
    569         __ Max_sB(dst, lhs, rhs);
    570       }
    571       break;
    572     case Primitive::kPrimChar:
    573     case Primitive::kPrimShort:
    574       DCHECK_EQ(8u, instruction->GetVectorLength());
    575       if (instruction->IsUnsigned()) {
    576         __ Max_uH(dst, lhs, rhs);
    577       } else {
    578         __ Max_sH(dst, lhs, rhs);
    579       }
    580       break;
    581     case Primitive::kPrimInt:
    582       DCHECK_EQ(4u, instruction->GetVectorLength());
    583       if (instruction->IsUnsigned()) {
    584         __ Max_uW(dst, lhs, rhs);
    585       } else {
    586         __ Max_sW(dst, lhs, rhs);
    587       }
    588       break;
    589     case Primitive::kPrimLong:
    590       DCHECK_EQ(2u, instruction->GetVectorLength());
    591       if (instruction->IsUnsigned()) {
    592         __ Max_uD(dst, lhs, rhs);
    593       } else {
    594         __ Max_sD(dst, lhs, rhs);
    595       }
    596       break;
    597     // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
    598     // TODO: Fix max(x, NaN) cases for float and double.
    599     case Primitive::kPrimFloat:
    600       DCHECK_EQ(4u, instruction->GetVectorLength());
    601       DCHECK(!instruction->IsUnsigned());
    602       __ FmaxW(dst, lhs, rhs);
    603       break;
    604     case Primitive::kPrimDouble:
    605       DCHECK_EQ(2u, instruction->GetVectorLength());
    606       DCHECK(!instruction->IsUnsigned());
    607       __ FmaxD(dst, lhs, rhs);
    608       break;
    609     default:
    610       LOG(FATAL) << "Unsupported SIMD type";
    611       UNREACHABLE();
    612   }
    613 }
    614 
    615 void LocationsBuilderMIPS64::VisitVecAnd(HVecAnd* instruction) {
    616   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    617 }
    618 
    619 void InstructionCodeGeneratorMIPS64::VisitVecAnd(HVecAnd* instruction) {
    620   LocationSummary* locations = instruction->GetLocations();
    621   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    622   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    623   VectorRegister dst = VectorRegisterFrom(locations->Out());
    624   switch (instruction->GetPackedType()) {
    625     case Primitive::kPrimBoolean:
    626     case Primitive::kPrimByte:
    627     case Primitive::kPrimChar:
    628     case Primitive::kPrimShort:
    629     case Primitive::kPrimInt:
    630     case Primitive::kPrimLong:
    631     case Primitive::kPrimFloat:
    632     case Primitive::kPrimDouble:
    633       DCHECK_LE(2u, instruction->GetVectorLength());
    634       DCHECK_LE(instruction->GetVectorLength(), 16u);
    635       __ AndV(dst, lhs, rhs);  // lanes do not matter
    636       break;
    637     default:
    638       LOG(FATAL) << "Unsupported SIMD type";
    639       UNREACHABLE();
    640   }
    641 }
    642 
    643 void LocationsBuilderMIPS64::VisitVecAndNot(HVecAndNot* instruction) {
    644   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    645 }
    646 
    647 void InstructionCodeGeneratorMIPS64::VisitVecAndNot(HVecAndNot* instruction) {
    648   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    649 }
    650 
    651 void LocationsBuilderMIPS64::VisitVecOr(HVecOr* instruction) {
    652   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    653 }
    654 
    655 void InstructionCodeGeneratorMIPS64::VisitVecOr(HVecOr* instruction) {
    656   LocationSummary* locations = instruction->GetLocations();
    657   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    658   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    659   VectorRegister dst = VectorRegisterFrom(locations->Out());
    660   switch (instruction->GetPackedType()) {
    661     case Primitive::kPrimBoolean:
    662     case Primitive::kPrimByte:
    663     case Primitive::kPrimChar:
    664     case Primitive::kPrimShort:
    665     case Primitive::kPrimInt:
    666     case Primitive::kPrimLong:
    667     case Primitive::kPrimFloat:
    668     case Primitive::kPrimDouble:
    669       DCHECK_LE(2u, instruction->GetVectorLength());
    670       DCHECK_LE(instruction->GetVectorLength(), 16u);
    671       __ OrV(dst, lhs, rhs);  // lanes do not matter
    672       break;
    673     default:
    674       LOG(FATAL) << "Unsupported SIMD type";
    675       UNREACHABLE();
    676   }
    677 }
    678 
    679 void LocationsBuilderMIPS64::VisitVecXor(HVecXor* instruction) {
    680   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    681 }
    682 
    683 void InstructionCodeGeneratorMIPS64::VisitVecXor(HVecXor* instruction) {
    684   LocationSummary* locations = instruction->GetLocations();
    685   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    686   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    687   VectorRegister dst = VectorRegisterFrom(locations->Out());
    688   switch (instruction->GetPackedType()) {
    689     case Primitive::kPrimBoolean:
    690     case Primitive::kPrimByte:
    691     case Primitive::kPrimChar:
    692     case Primitive::kPrimShort:
    693     case Primitive::kPrimInt:
    694     case Primitive::kPrimLong:
    695     case Primitive::kPrimFloat:
    696     case Primitive::kPrimDouble:
    697       DCHECK_LE(2u, instruction->GetVectorLength());
    698       DCHECK_LE(instruction->GetVectorLength(), 16u);
    699       __ XorV(dst, lhs, rhs);  // lanes do not matter
    700       break;
    701     default:
    702       LOG(FATAL) << "Unsupported SIMD type";
    703       UNREACHABLE();
    704   }
    705 }
    706 
    707 // Helper to set up locations for vector shift operations.
    708 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
    709   LocationSummary* locations = new (arena) LocationSummary(instruction);
    710   switch (instruction->GetPackedType()) {
    711     case Primitive::kPrimByte:
    712     case Primitive::kPrimChar:
    713     case Primitive::kPrimShort:
    714     case Primitive::kPrimInt:
    715     case Primitive::kPrimLong:
    716       locations->SetInAt(0, Location::RequiresFpuRegister());
    717       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
    718       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    719       break;
    720     default:
    721       LOG(FATAL) << "Unsupported SIMD type";
    722       UNREACHABLE();
    723   }
    724 }
    725 
    726 void LocationsBuilderMIPS64::VisitVecShl(HVecShl* instruction) {
    727   CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
    728 }
    729 
    730 void InstructionCodeGeneratorMIPS64::VisitVecShl(HVecShl* instruction) {
    731   LocationSummary* locations = instruction->GetLocations();
    732   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    733   VectorRegister dst = VectorRegisterFrom(locations->Out());
    734   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    735   switch (instruction->GetPackedType()) {
    736     case Primitive::kPrimByte:
    737       DCHECK_EQ(16u, instruction->GetVectorLength());
    738       __ SlliB(dst, lhs, value);
    739       break;
    740     case Primitive::kPrimChar:
    741     case Primitive::kPrimShort:
    742       DCHECK_EQ(8u, instruction->GetVectorLength());
    743       __ SlliH(dst, lhs, value);
    744       break;
    745     case Primitive::kPrimInt:
    746       DCHECK_EQ(4u, instruction->GetVectorLength());
    747       __ SlliW(dst, lhs, value);
    748       break;
    749     case Primitive::kPrimLong:
    750       DCHECK_EQ(2u, instruction->GetVectorLength());
    751       __ SlliD(dst, lhs, value);
    752       break;
    753     default:
    754       LOG(FATAL) << "Unsupported SIMD type";
    755       UNREACHABLE();
    756   }
    757 }
    758 
    759 void LocationsBuilderMIPS64::VisitVecShr(HVecShr* instruction) {
    760   CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
    761 }
    762 
    763 void InstructionCodeGeneratorMIPS64::VisitVecShr(HVecShr* instruction) {
    764   LocationSummary* locations = instruction->GetLocations();
    765   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    766   VectorRegister dst = VectorRegisterFrom(locations->Out());
    767   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    768   switch (instruction->GetPackedType()) {
    769     case Primitive::kPrimByte:
    770       DCHECK_EQ(16u, instruction->GetVectorLength());
    771       __ SraiB(dst, lhs, value);
    772       break;
    773     case Primitive::kPrimChar:
    774     case Primitive::kPrimShort:
    775       DCHECK_EQ(8u, instruction->GetVectorLength());
    776       __ SraiH(dst, lhs, value);
    777       break;
    778     case Primitive::kPrimInt:
    779       DCHECK_EQ(4u, instruction->GetVectorLength());
    780       __ SraiW(dst, lhs, value);
    781       break;
    782     case Primitive::kPrimLong:
    783       DCHECK_EQ(2u, instruction->GetVectorLength());
    784       __ SraiD(dst, lhs, value);
    785       break;
    786     default:
    787       LOG(FATAL) << "Unsupported SIMD type";
    788       UNREACHABLE();
    789   }
    790 }
    791 
    792 void LocationsBuilderMIPS64::VisitVecUShr(HVecUShr* instruction) {
    793   CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
    794 }
    795 
    796 void InstructionCodeGeneratorMIPS64::VisitVecUShr(HVecUShr* instruction) {
    797   LocationSummary* locations = instruction->GetLocations();
    798   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    799   VectorRegister dst = VectorRegisterFrom(locations->Out());
    800   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    801   switch (instruction->GetPackedType()) {
    802     case Primitive::kPrimByte:
    803       DCHECK_EQ(16u, instruction->GetVectorLength());
    804       __ SrliB(dst, lhs, value);
    805       break;
    806     case Primitive::kPrimChar:
    807     case Primitive::kPrimShort:
    808       DCHECK_EQ(8u, instruction->GetVectorLength());
    809       __ SrliH(dst, lhs, value);
    810       break;
    811     case Primitive::kPrimInt:
    812       DCHECK_EQ(4u, instruction->GetVectorLength());
    813       __ SrliW(dst, lhs, value);
    814       break;
    815     case Primitive::kPrimLong:
    816       DCHECK_EQ(2u, instruction->GetVectorLength());
    817       __ SrliD(dst, lhs, value);
    818       break;
    819     default:
    820       LOG(FATAL) << "Unsupported SIMD type";
    821       UNREACHABLE();
    822   }
    823 }
    824 
    825 void LocationsBuilderMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
    826   LOG(FATAL) << "No SIMD for " << instr->GetId();
    827 }
    828 
    829 void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
    830   LOG(FATAL) << "No SIMD for " << instr->GetId();
    831 }
    832 
    833 // Helper to set up locations for vector memory operations.
    834 static void CreateVecMemLocations(ArenaAllocator* arena,
    835                                   HVecMemoryOperation* instruction,
    836                                   bool is_load) {
    837   LocationSummary* locations = new (arena) LocationSummary(instruction);
    838   switch (instruction->GetPackedType()) {
    839     case Primitive::kPrimBoolean:
    840     case Primitive::kPrimByte:
    841     case Primitive::kPrimChar:
    842     case Primitive::kPrimShort:
    843     case Primitive::kPrimInt:
    844     case Primitive::kPrimLong:
    845     case Primitive::kPrimFloat:
    846     case Primitive::kPrimDouble:
    847       locations->SetInAt(0, Location::RequiresRegister());
    848       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
    849       if (is_load) {
    850         locations->SetOut(Location::RequiresFpuRegister());
    851       } else {
    852         locations->SetInAt(2, Location::RequiresFpuRegister());
    853       }
    854       break;
    855     default:
    856       LOG(FATAL) << "Unsupported SIMD type";
    857       UNREACHABLE();
    858   }
    859 }
    860 
    861 // Helper to prepare register and offset for vector memory operations. Returns the offset and sets
    862 // the output parameter adjusted_base to the original base or to a reserved temporary register (AT).
    863 int32_t InstructionCodeGeneratorMIPS64::VecAddress(LocationSummary* locations,
    864                                                    size_t size,
    865                                                    /* out */ GpuRegister* adjusted_base) {
    866   GpuRegister base = locations->InAt(0).AsRegister<GpuRegister>();
    867   Location index = locations->InAt(1);
    868   int scale = TIMES_1;
    869   switch (size) {
    870     case 2: scale = TIMES_2; break;
    871     case 4: scale = TIMES_4; break;
    872     case 8: scale = TIMES_8; break;
    873     default: break;
    874   }
    875   int32_t offset = mirror::Array::DataOffset(size).Int32Value();
    876 
    877   if (index.IsConstant()) {
    878     offset += index.GetConstant()->AsIntConstant()->GetValue() << scale;
    879     __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale);
    880     *adjusted_base = base;
    881   } else {
    882     GpuRegister index_reg = index.AsRegister<GpuRegister>();
    883     if (scale != TIMES_1) {
    884       __ Dlsa(AT, index_reg, base, scale);
    885     } else {
    886       __ Daddu(AT, base, index_reg);
    887     }
    888     *adjusted_base = AT;
    889   }
    890   return offset;
    891 }
    892 
    893 void LocationsBuilderMIPS64::VisitVecLoad(HVecLoad* instruction) {
    894   CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ true);
    895 }
    896 
    897 void InstructionCodeGeneratorMIPS64::VisitVecLoad(HVecLoad* instruction) {
    898   LocationSummary* locations = instruction->GetLocations();
    899   size_t size = Primitive::ComponentSize(instruction->GetPackedType());
    900   VectorRegister reg = VectorRegisterFrom(locations->Out());
    901   GpuRegister base;
    902   int32_t offset = VecAddress(locations, size, &base);
    903   switch (instruction->GetPackedType()) {
    904     case Primitive::kPrimBoolean:
    905     case Primitive::kPrimByte:
    906       DCHECK_EQ(16u, instruction->GetVectorLength());
    907       __ LdB(reg, base, offset);
    908       break;
    909     case Primitive::kPrimChar:
    910     case Primitive::kPrimShort:
    911       // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
    912       // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
    913       // loads and stores.
    914       // TODO: Implement support for StringCharAt.
    915       DCHECK(!instruction->IsStringCharAt());
    916       DCHECK_EQ(8u, instruction->GetVectorLength());
    917       __ LdH(reg, base, offset);
    918       break;
    919     case Primitive::kPrimInt:
    920     case Primitive::kPrimFloat:
    921       DCHECK_EQ(4u, instruction->GetVectorLength());
    922       __ LdW(reg, base, offset);
    923       break;
    924     case Primitive::kPrimLong:
    925     case Primitive::kPrimDouble:
    926       DCHECK_EQ(2u, instruction->GetVectorLength());
    927       __ LdD(reg, base, offset);
    928       break;
    929     default:
    930       LOG(FATAL) << "Unsupported SIMD type";
    931       UNREACHABLE();
    932   }
    933 }
    934 
    935 void LocationsBuilderMIPS64::VisitVecStore(HVecStore* instruction) {
    936   CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ false);
    937 }
    938 
    939 void InstructionCodeGeneratorMIPS64::VisitVecStore(HVecStore* instruction) {
    940   LocationSummary* locations = instruction->GetLocations();
    941   size_t size = Primitive::ComponentSize(instruction->GetPackedType());
    942   VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
    943   GpuRegister base;
    944   int32_t offset = VecAddress(locations, size, &base);
    945   switch (instruction->GetPackedType()) {
    946     case Primitive::kPrimBoolean:
    947     case Primitive::kPrimByte:
    948       DCHECK_EQ(16u, instruction->GetVectorLength());
    949       __ StB(reg, base, offset);
    950       break;
    951     case Primitive::kPrimChar:
    952     case Primitive::kPrimShort:
    953       DCHECK_EQ(8u, instruction->GetVectorLength());
    954       __ StH(reg, base, offset);
    955       break;
    956     case Primitive::kPrimInt:
    957     case Primitive::kPrimFloat:
    958       DCHECK_EQ(4u, instruction->GetVectorLength());
    959       __ StW(reg, base, offset);
    960       break;
    961     case Primitive::kPrimLong:
    962     case Primitive::kPrimDouble:
    963       DCHECK_EQ(2u, instruction->GetVectorLength());
    964       __ StD(reg, base, offset);
    965       break;
    966     default:
    967       LOG(FATAL) << "Unsupported SIMD type";
    968       UNREACHABLE();
    969   }
    970 }
    971 
    972 #undef __
    973 
    974 }  // namespace mips64
    975 }  // namespace art
    976