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()->GetAllocator()) LocationSummary(instruction);
     28   switch (instruction->GetPackedType()) {
     29     case DataType::Type::kBool:
     30     case DataType::Type::kUint8:
     31     case DataType::Type::kInt8:
     32     case DataType::Type::kUint16:
     33     case DataType::Type::kInt16:
     34     case DataType::Type::kInt32:
     35     case DataType::Type::kInt64:
     36       locations->SetInAt(0, Location::RequiresRegister());
     37       locations->SetOut(Location::RequiresFpuRegister());
     38       break;
     39     case DataType::Type::kFloat32:
     40     case DataType::Type::kFloat64:
     41       locations->SetInAt(0, Location::RequiresFpuRegister());
     42       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
     43       break;
     44     default:
     45       LOG(FATAL) << "Unsupported SIMD type";
     46       UNREACHABLE();
     47   }
     48 }
     49 
     50 void InstructionCodeGeneratorMIPS::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
     51   LocationSummary* locations = instruction->GetLocations();
     52   VectorRegister dst = VectorRegisterFrom(locations->Out());
     53   switch (instruction->GetPackedType()) {
     54     case DataType::Type::kBool:
     55     case DataType::Type::kUint8:
     56     case DataType::Type::kInt8:
     57       DCHECK_EQ(16u, instruction->GetVectorLength());
     58       __ FillB(dst, locations->InAt(0).AsRegister<Register>());
     59       break;
     60     case DataType::Type::kUint16:
     61     case DataType::Type::kInt16:
     62       DCHECK_EQ(8u, instruction->GetVectorLength());
     63       __ FillH(dst, locations->InAt(0).AsRegister<Register>());
     64       break;
     65     case DataType::Type::kInt32:
     66       DCHECK_EQ(4u, instruction->GetVectorLength());
     67       __ FillW(dst, locations->InAt(0).AsRegister<Register>());
     68       break;
     69     case DataType::Type::kInt64:
     70       DCHECK_EQ(2u, instruction->GetVectorLength());
     71       __ InsertW(static_cast<VectorRegister>(FTMP),
     72                  locations->InAt(0).AsRegisterPairLow<Register>(),
     73                  0);
     74       __ InsertW(static_cast<VectorRegister>(FTMP),
     75                  locations->InAt(0).AsRegisterPairHigh<Register>(),
     76                  1);
     77       __ ReplicateFPToVectorRegister(dst, FTMP, /* is_double */ true);
     78       break;
     79     case DataType::Type::kFloat32:
     80       DCHECK_EQ(4u, instruction->GetVectorLength());
     81       __ ReplicateFPToVectorRegister(dst,
     82                                      locations->InAt(0).AsFpuRegister<FRegister>(),
     83                                      /* is_double */ false);
     84       break;
     85     case DataType::Type::kFloat64:
     86       DCHECK_EQ(2u, instruction->GetVectorLength());
     87       __ ReplicateFPToVectorRegister(dst,
     88                                      locations->InAt(0).AsFpuRegister<FRegister>(),
     89                                      /* is_double */ true);
     90       break;
     91     default:
     92       LOG(FATAL) << "Unsupported SIMD type";
     93       UNREACHABLE();
     94   }
     95 }
     96 
     97 void LocationsBuilderMIPS::VisitVecExtractScalar(HVecExtractScalar* instruction) {
     98   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
     99   switch (instruction->GetPackedType()) {
    100     case DataType::Type::kBool:
    101     case DataType::Type::kUint8:
    102     case DataType::Type::kInt8:
    103     case DataType::Type::kUint16:
    104     case DataType::Type::kInt16:
    105     case DataType::Type::kInt32:
    106     case DataType::Type::kInt64:
    107       locations->SetInAt(0, Location::RequiresFpuRegister());
    108       locations->SetOut(Location::RequiresRegister());
    109       break;
    110     case DataType::Type::kFloat32:
    111     case DataType::Type::kFloat64:
    112       locations->SetInAt(0, Location::RequiresFpuRegister());
    113       locations->SetOut(Location::SameAsFirstInput());
    114       break;
    115     default:
    116       LOG(FATAL) << "Unsupported SIMD type";
    117       UNREACHABLE();
    118   }
    119 }
    120 
    121 void InstructionCodeGeneratorMIPS::VisitVecExtractScalar(HVecExtractScalar* instruction) {
    122   LocationSummary* locations = instruction->GetLocations();
    123   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    124   switch (instruction->GetPackedType()) {
    125     case DataType::Type::kInt32:
    126       DCHECK_EQ(4u, instruction->GetVectorLength());
    127       __ Copy_sW(locations->Out().AsRegister<Register>(), src, 0);
    128       break;
    129     case DataType::Type::kInt64:
    130       DCHECK_EQ(2u, instruction->GetVectorLength());
    131       __ Copy_sW(locations->Out().AsRegisterPairLow<Register>(), src, 0);
    132       __ Copy_sW(locations->Out().AsRegisterPairHigh<Register>(), src, 1);
    133       break;
    134     case DataType::Type::kFloat32:
    135     case DataType::Type::kFloat64:
    136       DCHECK_LE(2u, instruction->GetVectorLength());
    137       DCHECK_LE(instruction->GetVectorLength(), 4u);
    138       DCHECK(locations->InAt(0).Equals(locations->Out()));  // no code required
    139       break;
    140     default:
    141       LOG(FATAL) << "Unsupported SIMD type";
    142       UNREACHABLE();
    143   }
    144 }
    145 
    146 // Helper to set up locations for vector unary operations.
    147 static void CreateVecUnOpLocations(ArenaAllocator* allocator, HVecUnaryOperation* instruction) {
    148   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    149   DataType::Type type = instruction->GetPackedType();
    150   switch (type) {
    151     case DataType::Type::kBool:
    152       locations->SetInAt(0, Location::RequiresFpuRegister());
    153       locations->SetOut(Location::RequiresFpuRegister(),
    154                         instruction->IsVecNot() ? Location::kOutputOverlap
    155                                                 : Location::kNoOutputOverlap);
    156       break;
    157     case DataType::Type::kUint8:
    158     case DataType::Type::kInt8:
    159     case DataType::Type::kUint16:
    160     case DataType::Type::kInt16:
    161     case DataType::Type::kInt32:
    162     case DataType::Type::kInt64:
    163     case DataType::Type::kFloat32:
    164     case DataType::Type::kFloat64:
    165       locations->SetInAt(0, Location::RequiresFpuRegister());
    166       locations->SetOut(Location::RequiresFpuRegister(),
    167                         (instruction->IsVecNeg() || instruction->IsVecAbs() ||
    168                             (instruction->IsVecReduce() && type == DataType::Type::kInt64))
    169                             ? Location::kOutputOverlap
    170                             : Location::kNoOutputOverlap);
    171       break;
    172     default:
    173       LOG(FATAL) << "Unsupported SIMD type";
    174       UNREACHABLE();
    175   }
    176 }
    177 
    178 void LocationsBuilderMIPS::VisitVecReduce(HVecReduce* instruction) {
    179   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    180 }
    181 
    182 void InstructionCodeGeneratorMIPS::VisitVecReduce(HVecReduce* instruction) {
    183   LocationSummary* locations = instruction->GetLocations();
    184   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    185   VectorRegister dst = VectorRegisterFrom(locations->Out());
    186   VectorRegister tmp = static_cast<VectorRegister>(FTMP);
    187   switch (instruction->GetPackedType()) {
    188     case DataType::Type::kInt32:
    189       DCHECK_EQ(4u, instruction->GetVectorLength());
    190       switch (instruction->GetKind()) {
    191         case HVecReduce::kSum:
    192           __ Hadd_sD(tmp, src, src);
    193           __ IlvlD(dst, tmp, tmp);
    194           __ AddvW(dst, dst, tmp);
    195           break;
    196         case HVecReduce::kMin:
    197           __ IlvodW(tmp, src, src);
    198           __ Min_sW(tmp, src, tmp);
    199           __ IlvlW(dst, tmp, tmp);
    200           __ Min_sW(dst, dst, tmp);
    201           break;
    202         case HVecReduce::kMax:
    203           __ IlvodW(tmp, src, src);
    204           __ Max_sW(tmp, src, tmp);
    205           __ IlvlW(dst, tmp, tmp);
    206           __ Max_sW(dst, dst, tmp);
    207           break;
    208       }
    209       break;
    210     case DataType::Type::kInt64:
    211       DCHECK_EQ(2u, instruction->GetVectorLength());
    212       switch (instruction->GetKind()) {
    213         case HVecReduce::kSum:
    214           __ IlvlD(dst, src, src);
    215           __ AddvD(dst, dst, src);
    216           break;
    217         case HVecReduce::kMin:
    218           __ IlvlD(dst, src, src);
    219           __ Min_sD(dst, dst, src);
    220           break;
    221         case HVecReduce::kMax:
    222           __ IlvlD(dst, src, src);
    223           __ Max_sD(dst, dst, src);
    224           break;
    225       }
    226       break;
    227     default:
    228       LOG(FATAL) << "Unsupported SIMD type";
    229       UNREACHABLE();
    230   }
    231 }
    232 
    233 void LocationsBuilderMIPS::VisitVecCnv(HVecCnv* instruction) {
    234   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    235 }
    236 
    237 void InstructionCodeGeneratorMIPS::VisitVecCnv(HVecCnv* instruction) {
    238   LocationSummary* locations = instruction->GetLocations();
    239   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    240   VectorRegister dst = VectorRegisterFrom(locations->Out());
    241   DataType::Type from = instruction->GetInputType();
    242   DataType::Type to = instruction->GetResultType();
    243   if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) {
    244     DCHECK_EQ(4u, instruction->GetVectorLength());
    245     __ Ffint_sW(dst, src);
    246   } else {
    247     LOG(FATAL) << "Unsupported SIMD type";
    248   }
    249 }
    250 
    251 void LocationsBuilderMIPS::VisitVecNeg(HVecNeg* instruction) {
    252   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    253 }
    254 
    255 void InstructionCodeGeneratorMIPS::VisitVecNeg(HVecNeg* instruction) {
    256   LocationSummary* locations = instruction->GetLocations();
    257   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    258   VectorRegister dst = VectorRegisterFrom(locations->Out());
    259   switch (instruction->GetPackedType()) {
    260     case DataType::Type::kUint8:
    261     case DataType::Type::kInt8:
    262       DCHECK_EQ(16u, instruction->GetVectorLength());
    263       __ FillB(dst, ZERO);
    264       __ SubvB(dst, dst, src);
    265       break;
    266     case DataType::Type::kUint16:
    267     case DataType::Type::kInt16:
    268       DCHECK_EQ(8u, instruction->GetVectorLength());
    269       __ FillH(dst, ZERO);
    270       __ SubvH(dst, dst, src);
    271       break;
    272     case DataType::Type::kInt32:
    273       DCHECK_EQ(4u, instruction->GetVectorLength());
    274       __ FillW(dst, ZERO);
    275       __ SubvW(dst, dst, src);
    276       break;
    277     case DataType::Type::kInt64:
    278       DCHECK_EQ(2u, instruction->GetVectorLength());
    279       __ FillW(dst, ZERO);
    280       __ SubvD(dst, dst, src);
    281       break;
    282     case DataType::Type::kFloat32:
    283       DCHECK_EQ(4u, instruction->GetVectorLength());
    284       __ FillW(dst, ZERO);
    285       __ FsubW(dst, dst, src);
    286       break;
    287     case DataType::Type::kFloat64:
    288       DCHECK_EQ(2u, instruction->GetVectorLength());
    289       __ FillW(dst, ZERO);
    290       __ FsubD(dst, dst, src);
    291       break;
    292     default:
    293       LOG(FATAL) << "Unsupported SIMD type";
    294       UNREACHABLE();
    295   }
    296 }
    297 
    298 void LocationsBuilderMIPS::VisitVecAbs(HVecAbs* instruction) {
    299   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    300 }
    301 
    302 void InstructionCodeGeneratorMIPS::VisitVecAbs(HVecAbs* instruction) {
    303   LocationSummary* locations = instruction->GetLocations();
    304   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    305   VectorRegister dst = VectorRegisterFrom(locations->Out());
    306   switch (instruction->GetPackedType()) {
    307     case DataType::Type::kInt8:
    308       DCHECK_EQ(16u, instruction->GetVectorLength());
    309       __ FillB(dst, ZERO);       // all zeroes
    310       __ Add_aB(dst, dst, src);  // dst = abs(0) + abs(src)
    311       break;
    312     case DataType::Type::kInt16:
    313       DCHECK_EQ(8u, instruction->GetVectorLength());
    314       __ FillH(dst, ZERO);       // all zeroes
    315       __ Add_aH(dst, dst, src);  // dst = abs(0) + abs(src)
    316       break;
    317     case DataType::Type::kInt32:
    318       DCHECK_EQ(4u, instruction->GetVectorLength());
    319       __ FillW(dst, ZERO);       // all zeroes
    320       __ Add_aW(dst, dst, src);  // dst = abs(0) + abs(src)
    321       break;
    322     case DataType::Type::kInt64:
    323       DCHECK_EQ(2u, instruction->GetVectorLength());
    324       __ FillW(dst, ZERO);       // all zeroes
    325       __ Add_aD(dst, dst, src);  // dst = abs(0) + abs(src)
    326       break;
    327     case DataType::Type::kFloat32:
    328       DCHECK_EQ(4u, instruction->GetVectorLength());
    329       __ LdiW(dst, -1);          // all ones
    330       __ SrliW(dst, dst, 1);
    331       __ AndV(dst, dst, src);
    332       break;
    333     case DataType::Type::kFloat64:
    334       DCHECK_EQ(2u, instruction->GetVectorLength());
    335       __ LdiD(dst, -1);          // all ones
    336       __ SrliD(dst, dst, 1);
    337       __ AndV(dst, dst, src);
    338       break;
    339     default:
    340       LOG(FATAL) << "Unsupported SIMD type";
    341       UNREACHABLE();
    342   }
    343 }
    344 
    345 void LocationsBuilderMIPS::VisitVecNot(HVecNot* instruction) {
    346   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    347 }
    348 
    349 void InstructionCodeGeneratorMIPS::VisitVecNot(HVecNot* instruction) {
    350   LocationSummary* locations = instruction->GetLocations();
    351   VectorRegister src = VectorRegisterFrom(locations->InAt(0));
    352   VectorRegister dst = VectorRegisterFrom(locations->Out());
    353   switch (instruction->GetPackedType()) {
    354     case DataType::Type::kBool:  // special case boolean-not
    355       DCHECK_EQ(16u, instruction->GetVectorLength());
    356       __ LdiB(dst, 1);
    357       __ XorV(dst, dst, src);
    358       break;
    359     case DataType::Type::kUint8:
    360     case DataType::Type::kInt8:
    361     case DataType::Type::kUint16:
    362     case DataType::Type::kInt16:
    363     case DataType::Type::kInt32:
    364     case DataType::Type::kInt64:
    365     case DataType::Type::kFloat32:
    366     case DataType::Type::kFloat64:
    367       DCHECK_LE(2u, instruction->GetVectorLength());
    368       DCHECK_LE(instruction->GetVectorLength(), 16u);
    369       __ NorV(dst, src, src);  // lanes do not matter
    370       break;
    371     default:
    372       LOG(FATAL) << "Unsupported SIMD type";
    373       UNREACHABLE();
    374   }
    375 }
    376 
    377 // Helper to set up locations for vector binary operations.
    378 static void CreateVecBinOpLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
    379   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    380   switch (instruction->GetPackedType()) {
    381     case DataType::Type::kBool:
    382     case DataType::Type::kUint8:
    383     case DataType::Type::kInt8:
    384     case DataType::Type::kUint16:
    385     case DataType::Type::kInt16:
    386     case DataType::Type::kInt32:
    387     case DataType::Type::kInt64:
    388     case DataType::Type::kFloat32:
    389     case DataType::Type::kFloat64:
    390       locations->SetInAt(0, Location::RequiresFpuRegister());
    391       locations->SetInAt(1, Location::RequiresFpuRegister());
    392       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    393       break;
    394     default:
    395       LOG(FATAL) << "Unsupported SIMD type";
    396       UNREACHABLE();
    397   }
    398 }
    399 
    400 void LocationsBuilderMIPS::VisitVecAdd(HVecAdd* instruction) {
    401   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    402 }
    403 
    404 void InstructionCodeGeneratorMIPS::VisitVecAdd(HVecAdd* instruction) {
    405   LocationSummary* locations = instruction->GetLocations();
    406   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    407   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    408   VectorRegister dst = VectorRegisterFrom(locations->Out());
    409   switch (instruction->GetPackedType()) {
    410     case DataType::Type::kUint8:
    411     case DataType::Type::kInt8:
    412       DCHECK_EQ(16u, instruction->GetVectorLength());
    413       __ AddvB(dst, lhs, rhs);
    414       break;
    415     case DataType::Type::kUint16:
    416     case DataType::Type::kInt16:
    417       DCHECK_EQ(8u, instruction->GetVectorLength());
    418       __ AddvH(dst, lhs, rhs);
    419       break;
    420     case DataType::Type::kInt32:
    421       DCHECK_EQ(4u, instruction->GetVectorLength());
    422       __ AddvW(dst, lhs, rhs);
    423       break;
    424     case DataType::Type::kInt64:
    425       DCHECK_EQ(2u, instruction->GetVectorLength());
    426       __ AddvD(dst, lhs, rhs);
    427       break;
    428     case DataType::Type::kFloat32:
    429       DCHECK_EQ(4u, instruction->GetVectorLength());
    430       __ FaddW(dst, lhs, rhs);
    431       break;
    432     case DataType::Type::kFloat64:
    433       DCHECK_EQ(2u, instruction->GetVectorLength());
    434       __ FaddD(dst, lhs, rhs);
    435       break;
    436     default:
    437       LOG(FATAL) << "Unsupported SIMD type";
    438       UNREACHABLE();
    439   }
    440 }
    441 
    442 void LocationsBuilderMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    443   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    444 }
    445 
    446 void InstructionCodeGeneratorMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    447   LocationSummary* locations = instruction->GetLocations();
    448   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    449   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    450   VectorRegister dst = VectorRegisterFrom(locations->Out());
    451   switch (instruction->GetPackedType()) {
    452     case DataType::Type::kUint8:
    453       DCHECK_EQ(16u, instruction->GetVectorLength());
    454       instruction->IsRounded()
    455           ? __ Aver_uB(dst, lhs, rhs)
    456           : __ Ave_uB(dst, lhs, rhs);
    457       break;
    458     case DataType::Type::kInt8:
    459       DCHECK_EQ(16u, instruction->GetVectorLength());
    460       instruction->IsRounded()
    461           ? __ Aver_sB(dst, lhs, rhs)
    462           : __ Ave_sB(dst, lhs, rhs);
    463       break;
    464     case DataType::Type::kUint16:
    465       DCHECK_EQ(8u, instruction->GetVectorLength());
    466       instruction->IsRounded()
    467           ? __ Aver_uH(dst, lhs, rhs)
    468           : __ Ave_uH(dst, lhs, rhs);
    469       break;
    470     case DataType::Type::kInt16:
    471       DCHECK_EQ(8u, instruction->GetVectorLength());
    472       instruction->IsRounded()
    473           ? __ Aver_sH(dst, lhs, rhs)
    474           : __ Ave_sH(dst, lhs, rhs);
    475       break;
    476     default:
    477       LOG(FATAL) << "Unsupported SIMD type";
    478       UNREACHABLE();
    479   }
    480 }
    481 
    482 void LocationsBuilderMIPS::VisitVecSub(HVecSub* instruction) {
    483   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    484 }
    485 
    486 void InstructionCodeGeneratorMIPS::VisitVecSub(HVecSub* instruction) {
    487   LocationSummary* locations = instruction->GetLocations();
    488   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    489   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    490   VectorRegister dst = VectorRegisterFrom(locations->Out());
    491   switch (instruction->GetPackedType()) {
    492     case DataType::Type::kUint8:
    493     case DataType::Type::kInt8:
    494       DCHECK_EQ(16u, instruction->GetVectorLength());
    495       __ SubvB(dst, lhs, rhs);
    496       break;
    497     case DataType::Type::kUint16:
    498     case DataType::Type::kInt16:
    499       DCHECK_EQ(8u, instruction->GetVectorLength());
    500       __ SubvH(dst, lhs, rhs);
    501       break;
    502     case DataType::Type::kInt32:
    503       DCHECK_EQ(4u, instruction->GetVectorLength());
    504       __ SubvW(dst, lhs, rhs);
    505       break;
    506     case DataType::Type::kInt64:
    507       DCHECK_EQ(2u, instruction->GetVectorLength());
    508       __ SubvD(dst, lhs, rhs);
    509       break;
    510     case DataType::Type::kFloat32:
    511       DCHECK_EQ(4u, instruction->GetVectorLength());
    512       __ FsubW(dst, lhs, rhs);
    513       break;
    514     case DataType::Type::kFloat64:
    515       DCHECK_EQ(2u, instruction->GetVectorLength());
    516       __ FsubD(dst, lhs, rhs);
    517       break;
    518     default:
    519       LOG(FATAL) << "Unsupported SIMD type";
    520       UNREACHABLE();
    521   }
    522 }
    523 
    524 void LocationsBuilderMIPS::VisitVecMul(HVecMul* instruction) {
    525   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    526 }
    527 
    528 void InstructionCodeGeneratorMIPS::VisitVecMul(HVecMul* instruction) {
    529   LocationSummary* locations = instruction->GetLocations();
    530   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    531   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    532   VectorRegister dst = VectorRegisterFrom(locations->Out());
    533   switch (instruction->GetPackedType()) {
    534     case DataType::Type::kUint8:
    535     case DataType::Type::kInt8:
    536       DCHECK_EQ(16u, instruction->GetVectorLength());
    537       __ MulvB(dst, lhs, rhs);
    538       break;
    539     case DataType::Type::kUint16:
    540     case DataType::Type::kInt16:
    541       DCHECK_EQ(8u, instruction->GetVectorLength());
    542       __ MulvH(dst, lhs, rhs);
    543       break;
    544     case DataType::Type::kInt32:
    545       DCHECK_EQ(4u, instruction->GetVectorLength());
    546       __ MulvW(dst, lhs, rhs);
    547       break;
    548     case DataType::Type::kInt64:
    549       DCHECK_EQ(2u, instruction->GetVectorLength());
    550       __ MulvD(dst, lhs, rhs);
    551       break;
    552     case DataType::Type::kFloat32:
    553       DCHECK_EQ(4u, instruction->GetVectorLength());
    554       __ FmulW(dst, lhs, rhs);
    555       break;
    556     case DataType::Type::kFloat64:
    557       DCHECK_EQ(2u, instruction->GetVectorLength());
    558       __ FmulD(dst, lhs, rhs);
    559       break;
    560     default:
    561       LOG(FATAL) << "Unsupported SIMD type";
    562       UNREACHABLE();
    563   }
    564 }
    565 
    566 void LocationsBuilderMIPS::VisitVecDiv(HVecDiv* instruction) {
    567   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    568 }
    569 
    570 void InstructionCodeGeneratorMIPS::VisitVecDiv(HVecDiv* instruction) {
    571   LocationSummary* locations = instruction->GetLocations();
    572   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    573   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    574   VectorRegister dst = VectorRegisterFrom(locations->Out());
    575   switch (instruction->GetPackedType()) {
    576     case DataType::Type::kFloat32:
    577       DCHECK_EQ(4u, instruction->GetVectorLength());
    578       __ FdivW(dst, lhs, rhs);
    579       break;
    580     case DataType::Type::kFloat64:
    581       DCHECK_EQ(2u, instruction->GetVectorLength());
    582       __ FdivD(dst, lhs, rhs);
    583       break;
    584     default:
    585       LOG(FATAL) << "Unsupported SIMD type";
    586       UNREACHABLE();
    587   }
    588 }
    589 
    590 void LocationsBuilderMIPS::VisitVecMin(HVecMin* instruction) {
    591   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    592 }
    593 
    594 void InstructionCodeGeneratorMIPS::VisitVecMin(HVecMin* instruction) {
    595   LocationSummary* locations = instruction->GetLocations();
    596   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    597   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    598   VectorRegister dst = VectorRegisterFrom(locations->Out());
    599   switch (instruction->GetPackedType()) {
    600     case DataType::Type::kUint8:
    601       DCHECK_EQ(16u, instruction->GetVectorLength());
    602       __ Min_uB(dst, lhs, rhs);
    603       break;
    604     case DataType::Type::kInt8:
    605       DCHECK_EQ(16u, instruction->GetVectorLength());
    606       __ Min_sB(dst, lhs, rhs);
    607       break;
    608     case DataType::Type::kUint16:
    609       DCHECK_EQ(8u, instruction->GetVectorLength());
    610       __ Min_uH(dst, lhs, rhs);
    611       break;
    612     case DataType::Type::kInt16:
    613       DCHECK_EQ(8u, instruction->GetVectorLength());
    614       __ Min_sH(dst, lhs, rhs);
    615       break;
    616     case DataType::Type::kUint32:
    617       DCHECK_EQ(4u, instruction->GetVectorLength());
    618       __ Min_uW(dst, lhs, rhs);
    619       break;
    620     case DataType::Type::kInt32:
    621       DCHECK_EQ(4u, instruction->GetVectorLength());
    622       __ Min_sW(dst, lhs, rhs);
    623       break;
    624     case DataType::Type::kUint64:
    625       DCHECK_EQ(2u, instruction->GetVectorLength());
    626       __ Min_uD(dst, lhs, rhs);
    627       break;
    628     case DataType::Type::kInt64:
    629       DCHECK_EQ(2u, instruction->GetVectorLength());
    630       __ Min_sD(dst, lhs, rhs);
    631       break;
    632     // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
    633     // TODO: Fix min(x, NaN) cases for float and double.
    634     case DataType::Type::kFloat32:
    635       DCHECK_EQ(4u, instruction->GetVectorLength());
    636       __ FminW(dst, lhs, rhs);
    637       break;
    638     case DataType::Type::kFloat64:
    639       DCHECK_EQ(2u, instruction->GetVectorLength());
    640       __ FminD(dst, lhs, rhs);
    641       break;
    642     default:
    643       LOG(FATAL) << "Unsupported SIMD type";
    644       UNREACHABLE();
    645   }
    646 }
    647 
    648 void LocationsBuilderMIPS::VisitVecMax(HVecMax* instruction) {
    649   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    650 }
    651 
    652 void InstructionCodeGeneratorMIPS::VisitVecMax(HVecMax* instruction) {
    653   LocationSummary* locations = instruction->GetLocations();
    654   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    655   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    656   VectorRegister dst = VectorRegisterFrom(locations->Out());
    657   switch (instruction->GetPackedType()) {
    658     case DataType::Type::kUint8:
    659       DCHECK_EQ(16u, instruction->GetVectorLength());
    660       __ Max_uB(dst, lhs, rhs);
    661       break;
    662     case DataType::Type::kInt8:
    663       DCHECK_EQ(16u, instruction->GetVectorLength());
    664       __ Max_sB(dst, lhs, rhs);
    665       break;
    666     case DataType::Type::kUint16:
    667       DCHECK_EQ(8u, instruction->GetVectorLength());
    668       __ Max_uH(dst, lhs, rhs);
    669       break;
    670     case DataType::Type::kInt16:
    671       DCHECK_EQ(8u, instruction->GetVectorLength());
    672       __ Max_sH(dst, lhs, rhs);
    673       break;
    674     case DataType::Type::kUint32:
    675       DCHECK_EQ(4u, instruction->GetVectorLength());
    676       __ Max_uW(dst, lhs, rhs);
    677       break;
    678     case DataType::Type::kInt32:
    679       DCHECK_EQ(4u, instruction->GetVectorLength());
    680       __ Max_sW(dst, lhs, rhs);
    681       break;
    682     case DataType::Type::kUint64:
    683       DCHECK_EQ(2u, instruction->GetVectorLength());
    684       __ Max_uD(dst, lhs, rhs);
    685       break;
    686     case DataType::Type::kInt64:
    687       DCHECK_EQ(2u, instruction->GetVectorLength());
    688       __ Max_sD(dst, lhs, rhs);
    689       break;
    690     // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
    691     // TODO: Fix max(x, NaN) cases for float and double.
    692     case DataType::Type::kFloat32:
    693       DCHECK_EQ(4u, instruction->GetVectorLength());
    694       __ FmaxW(dst, lhs, rhs);
    695       break;
    696     case DataType::Type::kFloat64:
    697       DCHECK_EQ(2u, instruction->GetVectorLength());
    698       __ FmaxD(dst, lhs, rhs);
    699       break;
    700     default:
    701       LOG(FATAL) << "Unsupported SIMD type";
    702       UNREACHABLE();
    703   }
    704 }
    705 
    706 void LocationsBuilderMIPS::VisitVecAnd(HVecAnd* instruction) {
    707   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    708 }
    709 
    710 void InstructionCodeGeneratorMIPS::VisitVecAnd(HVecAnd* instruction) {
    711   LocationSummary* locations = instruction->GetLocations();
    712   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    713   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    714   VectorRegister dst = VectorRegisterFrom(locations->Out());
    715   switch (instruction->GetPackedType()) {
    716     case DataType::Type::kBool:
    717     case DataType::Type::kUint8:
    718     case DataType::Type::kInt8:
    719     case DataType::Type::kUint16:
    720     case DataType::Type::kInt16:
    721     case DataType::Type::kInt32:
    722     case DataType::Type::kInt64:
    723     case DataType::Type::kFloat32:
    724     case DataType::Type::kFloat64:
    725       DCHECK_LE(2u, instruction->GetVectorLength());
    726       DCHECK_LE(instruction->GetVectorLength(), 16u);
    727       __ AndV(dst, lhs, rhs);  // lanes do not matter
    728       break;
    729     default:
    730       LOG(FATAL) << "Unsupported SIMD type";
    731       UNREACHABLE();
    732   }
    733 }
    734 
    735 void LocationsBuilderMIPS::VisitVecAndNot(HVecAndNot* instruction) {
    736   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    737 }
    738 
    739 void InstructionCodeGeneratorMIPS::VisitVecAndNot(HVecAndNot* instruction) {
    740   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    741 }
    742 
    743 void LocationsBuilderMIPS::VisitVecOr(HVecOr* instruction) {
    744   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    745 }
    746 
    747 void InstructionCodeGeneratorMIPS::VisitVecOr(HVecOr* instruction) {
    748   LocationSummary* locations = instruction->GetLocations();
    749   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    750   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    751   VectorRegister dst = VectorRegisterFrom(locations->Out());
    752   switch (instruction->GetPackedType()) {
    753     case DataType::Type::kBool:
    754     case DataType::Type::kUint8:
    755     case DataType::Type::kInt8:
    756     case DataType::Type::kUint16:
    757     case DataType::Type::kInt16:
    758     case DataType::Type::kInt32:
    759     case DataType::Type::kInt64:
    760     case DataType::Type::kFloat32:
    761     case DataType::Type::kFloat64:
    762       DCHECK_LE(2u, instruction->GetVectorLength());
    763       DCHECK_LE(instruction->GetVectorLength(), 16u);
    764       __ OrV(dst, lhs, rhs);  // lanes do not matter
    765       break;
    766     default:
    767       LOG(FATAL) << "Unsupported SIMD type";
    768       UNREACHABLE();
    769   }
    770 }
    771 
    772 void LocationsBuilderMIPS::VisitVecXor(HVecXor* instruction) {
    773   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    774 }
    775 
    776 void InstructionCodeGeneratorMIPS::VisitVecXor(HVecXor* instruction) {
    777   LocationSummary* locations = instruction->GetLocations();
    778   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    779   VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
    780   VectorRegister dst = VectorRegisterFrom(locations->Out());
    781   switch (instruction->GetPackedType()) {
    782     case DataType::Type::kBool:
    783     case DataType::Type::kUint8:
    784     case DataType::Type::kInt8:
    785     case DataType::Type::kUint16:
    786     case DataType::Type::kInt16:
    787     case DataType::Type::kInt32:
    788     case DataType::Type::kInt64:
    789     case DataType::Type::kFloat32:
    790     case DataType::Type::kFloat64:
    791       DCHECK_LE(2u, instruction->GetVectorLength());
    792       DCHECK_LE(instruction->GetVectorLength(), 16u);
    793       __ XorV(dst, lhs, rhs);  // lanes do not matter
    794       break;
    795     default:
    796       LOG(FATAL) << "Unsupported SIMD type";
    797       UNREACHABLE();
    798   }
    799 }
    800 
    801 // Helper to set up locations for vector shift operations.
    802 static void CreateVecShiftLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
    803   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    804   switch (instruction->GetPackedType()) {
    805     case DataType::Type::kUint8:
    806     case DataType::Type::kInt8:
    807     case DataType::Type::kUint16:
    808     case DataType::Type::kInt16:
    809     case DataType::Type::kInt32:
    810     case DataType::Type::kInt64:
    811       locations->SetInAt(0, Location::RequiresFpuRegister());
    812       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
    813       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    814       break;
    815     default:
    816       LOG(FATAL) << "Unsupported SIMD type";
    817       UNREACHABLE();
    818   }
    819 }
    820 
    821 void LocationsBuilderMIPS::VisitVecShl(HVecShl* instruction) {
    822   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    823 }
    824 
    825 void InstructionCodeGeneratorMIPS::VisitVecShl(HVecShl* instruction) {
    826   LocationSummary* locations = instruction->GetLocations();
    827   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    828   VectorRegister dst = VectorRegisterFrom(locations->Out());
    829   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    830   switch (instruction->GetPackedType()) {
    831     case DataType::Type::kUint8:
    832     case DataType::Type::kInt8:
    833       DCHECK_EQ(16u, instruction->GetVectorLength());
    834       __ SlliB(dst, lhs, value);
    835       break;
    836     case DataType::Type::kUint16:
    837     case DataType::Type::kInt16:
    838       DCHECK_EQ(8u, instruction->GetVectorLength());
    839       __ SlliH(dst, lhs, value);
    840       break;
    841     case DataType::Type::kInt32:
    842       DCHECK_EQ(4u, instruction->GetVectorLength());
    843       __ SlliW(dst, lhs, value);
    844       break;
    845     case DataType::Type::kInt64:
    846       DCHECK_EQ(2u, instruction->GetVectorLength());
    847       __ SlliD(dst, lhs, value);
    848       break;
    849     default:
    850       LOG(FATAL) << "Unsupported SIMD type";
    851       UNREACHABLE();
    852   }
    853 }
    854 
    855 void LocationsBuilderMIPS::VisitVecShr(HVecShr* instruction) {
    856   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    857 }
    858 
    859 void InstructionCodeGeneratorMIPS::VisitVecShr(HVecShr* instruction) {
    860   LocationSummary* locations = instruction->GetLocations();
    861   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    862   VectorRegister dst = VectorRegisterFrom(locations->Out());
    863   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    864   switch (instruction->GetPackedType()) {
    865     case DataType::Type::kUint8:
    866     case DataType::Type::kInt8:
    867       DCHECK_EQ(16u, instruction->GetVectorLength());
    868       __ SraiB(dst, lhs, value);
    869       break;
    870     case DataType::Type::kUint16:
    871     case DataType::Type::kInt16:
    872       DCHECK_EQ(8u, instruction->GetVectorLength());
    873       __ SraiH(dst, lhs, value);
    874       break;
    875     case DataType::Type::kInt32:
    876       DCHECK_EQ(4u, instruction->GetVectorLength());
    877       __ SraiW(dst, lhs, value);
    878       break;
    879     case DataType::Type::kInt64:
    880       DCHECK_EQ(2u, instruction->GetVectorLength());
    881       __ SraiD(dst, lhs, value);
    882       break;
    883     default:
    884       LOG(FATAL) << "Unsupported SIMD type";
    885       UNREACHABLE();
    886   }
    887 }
    888 
    889 void LocationsBuilderMIPS::VisitVecUShr(HVecUShr* instruction) {
    890   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    891 }
    892 
    893 void InstructionCodeGeneratorMIPS::VisitVecUShr(HVecUShr* instruction) {
    894   LocationSummary* locations = instruction->GetLocations();
    895   VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
    896   VectorRegister dst = VectorRegisterFrom(locations->Out());
    897   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    898   switch (instruction->GetPackedType()) {
    899     case DataType::Type::kUint8:
    900     case DataType::Type::kInt8:
    901       DCHECK_EQ(16u, instruction->GetVectorLength());
    902       __ SrliB(dst, lhs, value);
    903       break;
    904     case DataType::Type::kUint16:
    905     case DataType::Type::kInt16:
    906       DCHECK_EQ(8u, instruction->GetVectorLength());
    907       __ SrliH(dst, lhs, value);
    908       break;
    909     case DataType::Type::kInt32:
    910       DCHECK_EQ(4u, instruction->GetVectorLength());
    911       __ SrliW(dst, lhs, value);
    912       break;
    913     case DataType::Type::kInt64:
    914       DCHECK_EQ(2u, instruction->GetVectorLength());
    915       __ SrliD(dst, lhs, value);
    916       break;
    917     default:
    918       LOG(FATAL) << "Unsupported SIMD type";
    919       UNREACHABLE();
    920   }
    921 }
    922 
    923 void LocationsBuilderMIPS::VisitVecSetScalars(HVecSetScalars* instruction) {
    924   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
    925 
    926   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
    927 
    928   HInstruction* input = instruction->InputAt(0);
    929   bool is_zero = IsZeroBitPattern(input);
    930 
    931   switch (instruction->GetPackedType()) {
    932     case DataType::Type::kBool:
    933     case DataType::Type::kUint8:
    934     case DataType::Type::kInt8:
    935     case DataType::Type::kUint16:
    936     case DataType::Type::kInt16:
    937     case DataType::Type::kInt32:
    938     case DataType::Type::kInt64:
    939       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
    940                                     : Location::RequiresRegister());
    941       locations->SetOut(Location::RequiresFpuRegister());
    942       break;
    943     case DataType::Type::kFloat32:
    944     case DataType::Type::kFloat64:
    945       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
    946                                     : Location::RequiresFpuRegister());
    947       locations->SetOut(Location::RequiresFpuRegister());
    948       break;
    949     default:
    950       LOG(FATAL) << "Unsupported SIMD type";
    951       UNREACHABLE();
    952   }
    953 }
    954 
    955 void InstructionCodeGeneratorMIPS::VisitVecSetScalars(HVecSetScalars* instruction) {
    956   LocationSummary* locations = instruction->GetLocations();
    957   VectorRegister dst = VectorRegisterFrom(locations->Out());
    958 
    959   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
    960 
    961   // Zero out all other elements first.
    962   __ FillW(dst, ZERO);
    963 
    964   // Shorthand for any type of zero.
    965   if (IsZeroBitPattern(instruction->InputAt(0))) {
    966     return;
    967   }
    968 
    969   // Set required elements.
    970   switch (instruction->GetPackedType()) {
    971     case DataType::Type::kBool:
    972     case DataType::Type::kUint8:
    973     case DataType::Type::kInt8:
    974       DCHECK_EQ(16u, instruction->GetVectorLength());
    975       __ InsertB(dst, locations->InAt(0).AsRegister<Register>(), 0);
    976       break;
    977     case DataType::Type::kUint16:
    978     case DataType::Type::kInt16:
    979       DCHECK_EQ(8u, instruction->GetVectorLength());
    980       __ InsertH(dst, locations->InAt(0).AsRegister<Register>(), 0);
    981       break;
    982     case DataType::Type::kInt32:
    983       DCHECK_EQ(4u, instruction->GetVectorLength());
    984       __ InsertW(dst, locations->InAt(0).AsRegister<Register>(), 0);
    985       break;
    986     case DataType::Type::kInt64:
    987       DCHECK_EQ(2u, instruction->GetVectorLength());
    988       __ InsertW(dst, locations->InAt(0).AsRegisterPairLow<Register>(), 0);
    989       __ InsertW(dst, locations->InAt(0).AsRegisterPairHigh<Register>(), 1);
    990       break;
    991     default:
    992       LOG(FATAL) << "Unsupported SIMD type";
    993       UNREACHABLE();
    994   }
    995 }
    996 
    997 // Helper to set up locations for vector accumulations.
    998 static void CreateVecAccumLocations(ArenaAllocator* allocator, HVecOperation* instruction) {
    999   LocationSummary* locations = new (allocator) LocationSummary(instruction);
   1000   switch (instruction->GetPackedType()) {
   1001     case DataType::Type::kUint8:
   1002     case DataType::Type::kInt8:
   1003     case DataType::Type::kUint16:
   1004     case DataType::Type::kInt16:
   1005     case DataType::Type::kInt32:
   1006     case DataType::Type::kInt64:
   1007       locations->SetInAt(0, Location::RequiresFpuRegister());
   1008       locations->SetInAt(1, Location::RequiresFpuRegister());
   1009       locations->SetInAt(2, Location::RequiresFpuRegister());
   1010       locations->SetOut(Location::SameAsFirstInput());
   1011       break;
   1012     default:
   1013       LOG(FATAL) << "Unsupported SIMD type";
   1014       UNREACHABLE();
   1015   }
   1016 }
   1017 
   1018 void LocationsBuilderMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
   1019   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
   1020 }
   1021 
   1022 void InstructionCodeGeneratorMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
   1023   LocationSummary* locations = instruction->GetLocations();
   1024   VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
   1025   VectorRegister left = VectorRegisterFrom(locations->InAt(1));
   1026   VectorRegister right = VectorRegisterFrom(locations->InAt(2));
   1027   switch (instruction->GetPackedType()) {
   1028     case DataType::Type::kUint8:
   1029     case DataType::Type::kInt8:
   1030       DCHECK_EQ(16u, instruction->GetVectorLength());
   1031       if (instruction->GetOpKind() == HInstruction::kAdd) {
   1032         __ MaddvB(acc, left, right);
   1033       } else {
   1034         __ MsubvB(acc, left, right);
   1035       }
   1036       break;
   1037     case DataType::Type::kUint16:
   1038     case DataType::Type::kInt16:
   1039       DCHECK_EQ(8u, instruction->GetVectorLength());
   1040       if (instruction->GetOpKind() == HInstruction::kAdd) {
   1041         __ MaddvH(acc, left, right);
   1042       } else {
   1043         __ MsubvH(acc, left, right);
   1044       }
   1045       break;
   1046     case DataType::Type::kInt32:
   1047       DCHECK_EQ(4u, instruction->GetVectorLength());
   1048       if (instruction->GetOpKind() == HInstruction::kAdd) {
   1049         __ MaddvW(acc, left, right);
   1050       } else {
   1051         __ MsubvW(acc, left, right);
   1052       }
   1053       break;
   1054     case DataType::Type::kInt64:
   1055       DCHECK_EQ(2u, instruction->GetVectorLength());
   1056       if (instruction->GetOpKind() == HInstruction::kAdd) {
   1057         __ MaddvD(acc, left, right);
   1058       } else {
   1059         __ MsubvD(acc, left, right);
   1060       }
   1061       break;
   1062     default:
   1063       LOG(FATAL) << "Unsupported SIMD type";
   1064       UNREACHABLE();
   1065   }
   1066 }
   1067 
   1068 void LocationsBuilderMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
   1069   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
   1070   LocationSummary* locations = instruction->GetLocations();
   1071   // All conversions require at least one temporary register.
   1072   locations->AddTemp(Location::RequiresFpuRegister());
   1073   // Some conversions require a second temporary register.
   1074   HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
   1075   HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
   1076   DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
   1077             HVecOperation::ToSignedType(b->GetPackedType()));
   1078   switch (a->GetPackedType()) {
   1079     case DataType::Type::kInt32:
   1080       if (instruction->GetPackedType() == DataType::Type::kInt32) {
   1081         break;
   1082       }
   1083       FALLTHROUGH_INTENDED;
   1084     case DataType::Type::kUint8:
   1085     case DataType::Type::kInt8:
   1086     case DataType::Type::kUint16:
   1087     case DataType::Type::kInt16:
   1088       locations->AddTemp(Location::RequiresFpuRegister());
   1089       break;
   1090     default:
   1091       break;
   1092   }
   1093 }
   1094 
   1095 void InstructionCodeGeneratorMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
   1096   LocationSummary* locations = instruction->GetLocations();
   1097   VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
   1098   VectorRegister left = VectorRegisterFrom(locations->InAt(1));
   1099   VectorRegister right = VectorRegisterFrom(locations->InAt(2));
   1100   VectorRegister tmp = static_cast<VectorRegister>(FTMP);
   1101   VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0));
   1102 
   1103   DCHECK(locations->InAt(0).Equals(locations->Out()));
   1104 
   1105   // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
   1106   HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
   1107   HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
   1108   DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
   1109             HVecOperation::ToSignedType(b->GetPackedType()));
   1110   switch (a->GetPackedType()) {
   1111     case DataType::Type::kUint8:
   1112     case DataType::Type::kInt8:
   1113       DCHECK_EQ(16u, a->GetVectorLength());
   1114       switch (instruction->GetPackedType()) {
   1115         case DataType::Type::kUint16:
   1116         case DataType::Type::kInt16: {
   1117           DCHECK_EQ(8u, instruction->GetVectorLength());
   1118           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
   1119           __ FillB(tmp, ZERO);
   1120           __ Hadd_sH(tmp1, left, tmp);
   1121           __ Hadd_sH(tmp2, right, tmp);
   1122           __ Asub_sH(tmp1, tmp1, tmp2);
   1123           __ AddvH(acc, acc, tmp1);
   1124           __ Hadd_sH(tmp1, tmp, left);
   1125           __ Hadd_sH(tmp2, tmp, right);
   1126           __ Asub_sH(tmp1, tmp1, tmp2);
   1127           __ AddvH(acc, acc, tmp1);
   1128           break;
   1129         }
   1130         case DataType::Type::kInt32: {
   1131           DCHECK_EQ(4u, instruction->GetVectorLength());
   1132           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
   1133           __ FillB(tmp, ZERO);
   1134           __ Hadd_sH(tmp1, left, tmp);
   1135           __ Hadd_sH(tmp2, right, tmp);
   1136           __ Asub_sH(tmp1, tmp1, tmp2);
   1137           __ Hadd_sW(tmp1, tmp1, tmp1);
   1138           __ AddvW(acc, acc, tmp1);
   1139           __ Hadd_sH(tmp1, tmp, left);
   1140           __ Hadd_sH(tmp2, tmp, right);
   1141           __ Asub_sH(tmp1, tmp1, tmp2);
   1142           __ Hadd_sW(tmp1, tmp1, tmp1);
   1143           __ AddvW(acc, acc, tmp1);
   1144           break;
   1145         }
   1146         case DataType::Type::kInt64: {
   1147           DCHECK_EQ(2u, instruction->GetVectorLength());
   1148           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
   1149           __ FillB(tmp, ZERO);
   1150           __ Hadd_sH(tmp1, left, tmp);
   1151           __ Hadd_sH(tmp2, right, tmp);
   1152           __ Asub_sH(tmp1, tmp1, tmp2);
   1153           __ Hadd_sW(tmp1, tmp1, tmp1);
   1154           __ Hadd_sD(tmp1, tmp1, tmp1);
   1155           __ AddvD(acc, acc, tmp1);
   1156           __ Hadd_sH(tmp1, tmp, left);
   1157           __ Hadd_sH(tmp2, tmp, right);
   1158           __ Asub_sH(tmp1, tmp1, tmp2);
   1159           __ Hadd_sW(tmp1, tmp1, tmp1);
   1160           __ Hadd_sD(tmp1, tmp1, tmp1);
   1161           __ AddvD(acc, acc, tmp1);
   1162           break;
   1163         }
   1164         default:
   1165           LOG(FATAL) << "Unsupported SIMD type";
   1166           UNREACHABLE();
   1167       }
   1168       break;
   1169     case DataType::Type::kUint16:
   1170     case DataType::Type::kInt16:
   1171       DCHECK_EQ(8u, a->GetVectorLength());
   1172       switch (instruction->GetPackedType()) {
   1173         case DataType::Type::kInt32: {
   1174           DCHECK_EQ(4u, instruction->GetVectorLength());
   1175           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
   1176           __ FillH(tmp, ZERO);
   1177           __ Hadd_sW(tmp1, left, tmp);
   1178           __ Hadd_sW(tmp2, right, tmp);
   1179           __ Asub_sW(tmp1, tmp1, tmp2);
   1180           __ AddvW(acc, acc, tmp1);
   1181           __ Hadd_sW(tmp1, tmp, left);
   1182           __ Hadd_sW(tmp2, tmp, right);
   1183           __ Asub_sW(tmp1, tmp1, tmp2);
   1184           __ AddvW(acc, acc, tmp1);
   1185           break;
   1186         }
   1187         case DataType::Type::kInt64: {
   1188           DCHECK_EQ(2u, instruction->GetVectorLength());
   1189           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
   1190           __ FillH(tmp, ZERO);
   1191           __ Hadd_sW(tmp1, left, tmp);
   1192           __ Hadd_sW(tmp2, right, tmp);
   1193           __ Asub_sW(tmp1, tmp1, tmp2);
   1194           __ Hadd_sD(tmp1, tmp1, tmp1);
   1195           __ AddvD(acc, acc, tmp1);
   1196           __ Hadd_sW(tmp1, tmp, left);
   1197           __ Hadd_sW(tmp2, tmp, right);
   1198           __ Asub_sW(tmp1, tmp1, tmp2);
   1199           __ Hadd_sD(tmp1, tmp1, tmp1);
   1200           __ AddvD(acc, acc, tmp1);
   1201           break;
   1202         }
   1203         default:
   1204           LOG(FATAL) << "Unsupported SIMD type";
   1205           UNREACHABLE();
   1206       }
   1207       break;
   1208     case DataType::Type::kInt32:
   1209       DCHECK_EQ(4u, a->GetVectorLength());
   1210       switch (instruction->GetPackedType()) {
   1211         case DataType::Type::kInt32: {
   1212           DCHECK_EQ(4u, instruction->GetVectorLength());
   1213           __ FillW(tmp, ZERO);
   1214           __ SubvW(tmp1, left, right);
   1215           __ Add_aW(tmp1, tmp1, tmp);
   1216           __ AddvW(acc, acc, tmp1);
   1217           break;
   1218         }
   1219         case DataType::Type::kInt64: {
   1220           DCHECK_EQ(2u, instruction->GetVectorLength());
   1221           VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
   1222           __ FillW(tmp, ZERO);
   1223           __ Hadd_sD(tmp1, left, tmp);
   1224           __ Hadd_sD(tmp2, right, tmp);
   1225           __ Asub_sD(tmp1, tmp1, tmp2);
   1226           __ AddvD(acc, acc, tmp1);
   1227           __ Hadd_sD(tmp1, tmp, left);
   1228           __ Hadd_sD(tmp2, tmp, right);
   1229           __ Asub_sD(tmp1, tmp1, tmp2);
   1230           __ AddvD(acc, acc, tmp1);
   1231           break;
   1232         }
   1233         default:
   1234           LOG(FATAL) << "Unsupported SIMD type";
   1235           UNREACHABLE();
   1236       }
   1237       break;
   1238     case DataType::Type::kInt64: {
   1239       DCHECK_EQ(2u, a->GetVectorLength());
   1240       switch (instruction->GetPackedType()) {
   1241         case DataType::Type::kInt64: {
   1242           DCHECK_EQ(2u, instruction->GetVectorLength());
   1243           __ FillW(tmp, ZERO);
   1244           __ SubvD(tmp1, left, right);
   1245           __ Add_aD(tmp1, tmp1, tmp);
   1246           __ AddvD(acc, acc, tmp1);
   1247           break;
   1248         }
   1249         default:
   1250           LOG(FATAL) << "Unsupported SIMD type";
   1251           UNREACHABLE();
   1252       }
   1253       break;
   1254     }
   1255     default:
   1256       LOG(FATAL) << "Unsupported SIMD type";
   1257       UNREACHABLE();
   1258   }
   1259 }
   1260 
   1261 // Helper to set up locations for vector memory operations.
   1262 static void CreateVecMemLocations(ArenaAllocator* allocator,
   1263                                   HVecMemoryOperation* instruction,
   1264                                   bool is_load) {
   1265   LocationSummary* locations = new (allocator) LocationSummary(instruction);
   1266   switch (instruction->GetPackedType()) {
   1267     case DataType::Type::kBool:
   1268     case DataType::Type::kUint8:
   1269     case DataType::Type::kInt8:
   1270     case DataType::Type::kUint16:
   1271     case DataType::Type::kInt16:
   1272     case DataType::Type::kInt32:
   1273     case DataType::Type::kInt64:
   1274     case DataType::Type::kFloat32:
   1275     case DataType::Type::kFloat64:
   1276       locations->SetInAt(0, Location::RequiresRegister());
   1277       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
   1278       if (is_load) {
   1279         locations->SetOut(Location::RequiresFpuRegister());
   1280       } else {
   1281         locations->SetInAt(2, Location::RequiresFpuRegister());
   1282       }
   1283       break;
   1284     default:
   1285       LOG(FATAL) << "Unsupported SIMD type";
   1286       UNREACHABLE();
   1287   }
   1288 }
   1289 
   1290 // Helper to prepare register and offset for vector memory operations. Returns the offset and sets
   1291 // the output parameter adjusted_base to the original base or to a reserved temporary register (AT).
   1292 int32_t InstructionCodeGeneratorMIPS::VecAddress(LocationSummary* locations,
   1293                                                  size_t size,
   1294                                                  /* out */ Register* adjusted_base) {
   1295   Register base = locations->InAt(0).AsRegister<Register>();
   1296   Location index = locations->InAt(1);
   1297   int scale = TIMES_1;
   1298   switch (size) {
   1299     case 2: scale = TIMES_2; break;
   1300     case 4: scale = TIMES_4; break;
   1301     case 8: scale = TIMES_8; break;
   1302     default: break;
   1303   }
   1304   int32_t offset = mirror::Array::DataOffset(size).Int32Value();
   1305 
   1306   if (index.IsConstant()) {
   1307     offset += index.GetConstant()->AsIntConstant()->GetValue() << scale;
   1308     __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale);
   1309     *adjusted_base = base;
   1310   } else {
   1311     Register index_reg = index.AsRegister<Register>();
   1312     if (scale != TIMES_1) {
   1313       __ Lsa(AT, index_reg, base, scale);
   1314     } else {
   1315       __ Addu(AT, base, index_reg);
   1316     }
   1317     *adjusted_base = AT;
   1318   }
   1319   return offset;
   1320 }
   1321 
   1322 void LocationsBuilderMIPS::VisitVecLoad(HVecLoad* instruction) {
   1323   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load */ true);
   1324 }
   1325 
   1326 void InstructionCodeGeneratorMIPS::VisitVecLoad(HVecLoad* instruction) {
   1327   LocationSummary* locations = instruction->GetLocations();
   1328   size_t size = DataType::Size(instruction->GetPackedType());
   1329   VectorRegister reg = VectorRegisterFrom(locations->Out());
   1330   Register base;
   1331   int32_t offset = VecAddress(locations, size, &base);
   1332   switch (instruction->GetPackedType()) {
   1333     case DataType::Type::kBool:
   1334     case DataType::Type::kUint8:
   1335     case DataType::Type::kInt8:
   1336       DCHECK_EQ(16u, instruction->GetVectorLength());
   1337       __ LdB(reg, base, offset);
   1338       break;
   1339     case DataType::Type::kUint16:
   1340     case DataType::Type::kInt16:
   1341       // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
   1342       // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
   1343       // loads and stores.
   1344       // TODO: Implement support for StringCharAt.
   1345       DCHECK(!instruction->IsStringCharAt());
   1346       DCHECK_EQ(8u, instruction->GetVectorLength());
   1347       __ LdH(reg, base, offset);
   1348       break;
   1349     case DataType::Type::kInt32:
   1350     case DataType::Type::kFloat32:
   1351       DCHECK_EQ(4u, instruction->GetVectorLength());
   1352       __ LdW(reg, base, offset);
   1353       break;
   1354     case DataType::Type::kInt64:
   1355     case DataType::Type::kFloat64:
   1356       DCHECK_EQ(2u, instruction->GetVectorLength());
   1357       __ LdD(reg, base, offset);
   1358       break;
   1359     default:
   1360       LOG(FATAL) << "Unsupported SIMD type";
   1361       UNREACHABLE();
   1362   }
   1363 }
   1364 
   1365 void LocationsBuilderMIPS::VisitVecStore(HVecStore* instruction) {
   1366   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load */ false);
   1367 }
   1368 
   1369 void InstructionCodeGeneratorMIPS::VisitVecStore(HVecStore* instruction) {
   1370   LocationSummary* locations = instruction->GetLocations();
   1371   size_t size = DataType::Size(instruction->GetPackedType());
   1372   VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
   1373   Register base;
   1374   int32_t offset = VecAddress(locations, size, &base);
   1375   switch (instruction->GetPackedType()) {
   1376     case DataType::Type::kBool:
   1377     case DataType::Type::kUint8:
   1378     case DataType::Type::kInt8:
   1379       DCHECK_EQ(16u, instruction->GetVectorLength());
   1380       __ StB(reg, base, offset);
   1381       break;
   1382     case DataType::Type::kUint16:
   1383     case DataType::Type::kInt16:
   1384       DCHECK_EQ(8u, instruction->GetVectorLength());
   1385       __ StH(reg, base, offset);
   1386       break;
   1387     case DataType::Type::kInt32:
   1388     case DataType::Type::kFloat32:
   1389       DCHECK_EQ(4u, instruction->GetVectorLength());
   1390       __ StW(reg, base, offset);
   1391       break;
   1392     case DataType::Type::kInt64:
   1393     case DataType::Type::kFloat64:
   1394       DCHECK_EQ(2u, instruction->GetVectorLength());
   1395       __ StD(reg, base, offset);
   1396       break;
   1397     default:
   1398       LOG(FATAL) << "Unsupported SIMD type";
   1399       UNREACHABLE();
   1400   }
   1401 }
   1402 
   1403 #undef __
   1404 
   1405 }  // namespace mips
   1406 }  // namespace art
   1407