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