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_arm_vixl.h"
     18 #include "mirror/array-inl.h"
     19 
     20 namespace vixl32 = vixl::aarch32;
     21 using namespace vixl32;  // NOLINT(build/namespaces)
     22 
     23 namespace art {
     24 namespace arm {
     25 
     26 using helpers::DRegisterFrom;
     27 using helpers::Int64ConstantFrom;
     28 using helpers::InputDRegisterAt;
     29 using helpers::InputRegisterAt;
     30 using helpers::OutputDRegister;
     31 using helpers::OutputRegister;
     32 using helpers::RegisterFrom;
     33 
     34 #define __ GetVIXLAssembler()->
     35 
     36 void LocationsBuilderARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
     37   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
     38   switch (instruction->GetPackedType()) {
     39     case DataType::Type::kBool:
     40     case DataType::Type::kUint8:
     41     case DataType::Type::kInt8:
     42     case DataType::Type::kUint16:
     43     case DataType::Type::kInt16:
     44     case DataType::Type::kInt32:
     45       locations->SetInAt(0, Location::RequiresRegister());
     46       locations->SetOut(Location::RequiresFpuRegister());
     47       break;
     48     default:
     49       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
     50       UNREACHABLE();
     51   }
     52 }
     53 
     54 void InstructionCodeGeneratorARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
     55   LocationSummary* locations = instruction->GetLocations();
     56   vixl32::DRegister dst = DRegisterFrom(locations->Out());
     57   switch (instruction->GetPackedType()) {
     58     case DataType::Type::kBool:
     59     case DataType::Type::kUint8:
     60     case DataType::Type::kInt8:
     61       DCHECK_EQ(8u, instruction->GetVectorLength());
     62       __ Vdup(Untyped8, dst, InputRegisterAt(instruction, 0));
     63       break;
     64     case DataType::Type::kUint16:
     65     case DataType::Type::kInt16:
     66       DCHECK_EQ(4u, instruction->GetVectorLength());
     67       __ Vdup(Untyped16, dst, InputRegisterAt(instruction, 0));
     68       break;
     69     case DataType::Type::kInt32:
     70       DCHECK_EQ(2u, instruction->GetVectorLength());
     71       __ Vdup(Untyped32, dst, InputRegisterAt(instruction, 0));
     72       break;
     73     default:
     74       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
     75       UNREACHABLE();
     76   }
     77 }
     78 
     79 void LocationsBuilderARMVIXL::VisitVecExtractScalar(HVecExtractScalar* instruction) {
     80   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
     81   switch (instruction->GetPackedType()) {
     82     case DataType::Type::kInt32:
     83       locations->SetInAt(0, Location::RequiresFpuRegister());
     84       locations->SetOut(Location::RequiresRegister());
     85       break;
     86     default:
     87       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
     88       UNREACHABLE();
     89   }
     90 }
     91 
     92 void InstructionCodeGeneratorARMVIXL::VisitVecExtractScalar(HVecExtractScalar* instruction) {
     93   LocationSummary* locations = instruction->GetLocations();
     94   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
     95   switch (instruction->GetPackedType()) {
     96     case DataType::Type::kInt32:
     97       DCHECK_EQ(2u, instruction->GetVectorLength());
     98       __ Vmov(OutputRegister(instruction), DRegisterLane(src, 0));
     99       break;
    100     default:
    101       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    102       UNREACHABLE();
    103   }
    104 }
    105 
    106 // Helper to set up locations for vector unary operations.
    107 static void CreateVecUnOpLocations(ArenaAllocator* allocator, HVecUnaryOperation* instruction) {
    108   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    109   switch (instruction->GetPackedType()) {
    110     case DataType::Type::kBool:
    111       locations->SetInAt(0, Location::RequiresFpuRegister());
    112       locations->SetOut(Location::RequiresFpuRegister(),
    113                         instruction->IsVecNot() ? Location::kOutputOverlap
    114                                                 : Location::kNoOutputOverlap);
    115       break;
    116     case DataType::Type::kUint8:
    117     case DataType::Type::kInt8:
    118     case DataType::Type::kUint16:
    119     case DataType::Type::kInt16:
    120     case DataType::Type::kInt32:
    121       locations->SetInAt(0, Location::RequiresFpuRegister());
    122       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    123       break;
    124     default:
    125       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    126       UNREACHABLE();
    127   }
    128 }
    129 
    130 void LocationsBuilderARMVIXL::VisitVecReduce(HVecReduce* instruction) {
    131   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    132 }
    133 
    134 void InstructionCodeGeneratorARMVIXL::VisitVecReduce(HVecReduce* instruction) {
    135   LocationSummary* locations = instruction->GetLocations();
    136   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
    137   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    138   switch (instruction->GetPackedType()) {
    139     case DataType::Type::kInt32:
    140       DCHECK_EQ(2u, instruction->GetVectorLength());
    141       switch (instruction->GetReductionKind()) {
    142         case HVecReduce::kSum:
    143           __ Vpadd(DataTypeValue::I32, dst, src, src);
    144           break;
    145         case HVecReduce::kMin:
    146           __ Vpmin(DataTypeValue::S32, dst, src, src);
    147           break;
    148         case HVecReduce::kMax:
    149           __ Vpmax(DataTypeValue::S32, dst, src, src);
    150           break;
    151       }
    152       break;
    153     default:
    154       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    155       UNREACHABLE();
    156   }
    157 }
    158 
    159 void LocationsBuilderARMVIXL::VisitVecCnv(HVecCnv* instruction) {
    160   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    161 }
    162 
    163 void InstructionCodeGeneratorARMVIXL::VisitVecCnv(HVecCnv* instruction) {
    164   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    165 }
    166 
    167 void LocationsBuilderARMVIXL::VisitVecNeg(HVecNeg* instruction) {
    168   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    169 }
    170 
    171 void InstructionCodeGeneratorARMVIXL::VisitVecNeg(HVecNeg* instruction) {
    172   LocationSummary* locations = instruction->GetLocations();
    173   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
    174   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    175   switch (instruction->GetPackedType()) {
    176     case DataType::Type::kUint8:
    177     case DataType::Type::kInt8:
    178       DCHECK_EQ(8u, instruction->GetVectorLength());
    179       __ Vneg(DataTypeValue::S8, dst, src);
    180       break;
    181     case DataType::Type::kUint16:
    182     case DataType::Type::kInt16:
    183       DCHECK_EQ(4u, instruction->GetVectorLength());
    184       __ Vneg(DataTypeValue::S16, dst, src);
    185       break;
    186     case DataType::Type::kInt32:
    187       DCHECK_EQ(2u, instruction->GetVectorLength());
    188       __ Vneg(DataTypeValue::S32, dst, src);
    189       break;
    190     default:
    191       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    192       UNREACHABLE();
    193   }
    194 }
    195 
    196 void LocationsBuilderARMVIXL::VisitVecAbs(HVecAbs* instruction) {
    197   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    198 }
    199 
    200 void InstructionCodeGeneratorARMVIXL::VisitVecAbs(HVecAbs* instruction) {
    201   LocationSummary* locations = instruction->GetLocations();
    202   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
    203   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    204   switch (instruction->GetPackedType()) {
    205     case DataType::Type::kInt8:
    206       DCHECK_EQ(8u, instruction->GetVectorLength());
    207       __ Vabs(DataTypeValue::S8, dst, src);
    208       break;
    209     case DataType::Type::kInt16:
    210       DCHECK_EQ(4u, instruction->GetVectorLength());
    211       __ Vabs(DataTypeValue::S16, dst, src);
    212       break;
    213     case DataType::Type::kInt32:
    214       DCHECK_EQ(2u, instruction->GetVectorLength());
    215       __ Vabs(DataTypeValue::S32, dst, src);
    216       break;
    217     default:
    218       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    219       UNREACHABLE();
    220   }
    221 }
    222 
    223 void LocationsBuilderARMVIXL::VisitVecNot(HVecNot* instruction) {
    224   CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction);
    225 }
    226 
    227 void InstructionCodeGeneratorARMVIXL::VisitVecNot(HVecNot* instruction) {
    228   LocationSummary* locations = instruction->GetLocations();
    229   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
    230   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    231   switch (instruction->GetPackedType()) {
    232     case DataType::Type::kBool:  // special case boolean-not
    233       DCHECK_EQ(8u, instruction->GetVectorLength());
    234       __ Vmov(I8, dst, 1);
    235       __ Veor(dst, dst, src);
    236       break;
    237     case DataType::Type::kUint8:
    238     case DataType::Type::kInt8:
    239     case DataType::Type::kUint16:
    240     case DataType::Type::kInt16:
    241     case DataType::Type::kInt32:
    242       __ Vmvn(I8, dst, src);  // lanes do not matter
    243       break;
    244     default:
    245       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    246       UNREACHABLE();
    247   }
    248 }
    249 
    250 // Helper to set up locations for vector binary operations.
    251 static void CreateVecBinOpLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
    252   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    253   switch (instruction->GetPackedType()) {
    254     case DataType::Type::kBool:
    255     case DataType::Type::kUint8:
    256     case DataType::Type::kInt8:
    257     case DataType::Type::kUint16:
    258     case DataType::Type::kInt16:
    259     case DataType::Type::kInt32:
    260       locations->SetInAt(0, Location::RequiresFpuRegister());
    261       locations->SetInAt(1, Location::RequiresFpuRegister());
    262       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    263       break;
    264     default:
    265       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    266       UNREACHABLE();
    267   }
    268 }
    269 
    270 void LocationsBuilderARMVIXL::VisitVecAdd(HVecAdd* instruction) {
    271   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    272 }
    273 
    274 void InstructionCodeGeneratorARMVIXL::VisitVecAdd(HVecAdd* instruction) {
    275   LocationSummary* locations = instruction->GetLocations();
    276   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    277   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    278   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    279   switch (instruction->GetPackedType()) {
    280     case DataType::Type::kUint8:
    281     case DataType::Type::kInt8:
    282       DCHECK_EQ(8u, instruction->GetVectorLength());
    283       __ Vadd(I8, dst, lhs, rhs);
    284       break;
    285     case DataType::Type::kUint16:
    286     case DataType::Type::kInt16:
    287       DCHECK_EQ(4u, instruction->GetVectorLength());
    288       __ Vadd(I16, dst, lhs, rhs);
    289       break;
    290     case DataType::Type::kInt32:
    291       DCHECK_EQ(2u, instruction->GetVectorLength());
    292       __ Vadd(I32, dst, lhs, rhs);
    293       break;
    294     default:
    295       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    296       UNREACHABLE();
    297   }
    298 }
    299 
    300 void LocationsBuilderARMVIXL::VisitVecSaturationAdd(HVecSaturationAdd* instruction) {
    301   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    302 }
    303 
    304 void InstructionCodeGeneratorARMVIXL::VisitVecSaturationAdd(HVecSaturationAdd* instruction) {
    305   LocationSummary* locations = instruction->GetLocations();
    306   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    307   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    308   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    309   switch (instruction->GetPackedType()) {
    310     case DataType::Type::kUint8:
    311       DCHECK_EQ(8u, instruction->GetVectorLength());
    312       __ Vqadd(DataTypeValue::U8, dst, lhs, rhs);
    313       break;
    314     case DataType::Type::kInt8:
    315       DCHECK_EQ(8u, instruction->GetVectorLength());
    316       __ Vqadd(DataTypeValue::S8, dst, lhs, rhs);
    317       break;
    318     case DataType::Type::kUint16:
    319       DCHECK_EQ(4u, instruction->GetVectorLength());
    320       __ Vqadd(DataTypeValue::U16, dst, lhs, rhs);
    321       break;
    322     case DataType::Type::kInt16:
    323       DCHECK_EQ(4u, instruction->GetVectorLength());
    324       __ Vqadd(DataTypeValue::S16, dst, lhs, rhs);
    325       break;
    326     default:
    327       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    328       UNREACHABLE();
    329   }
    330 }
    331 
    332 void LocationsBuilderARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    333   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    334 }
    335 
    336 void InstructionCodeGeneratorARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    337   LocationSummary* locations = instruction->GetLocations();
    338   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    339   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    340   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    341   switch (instruction->GetPackedType()) {
    342     case DataType::Type::kUint8:
    343       DCHECK_EQ(8u, instruction->GetVectorLength());
    344       instruction->IsRounded()
    345           ? __ Vrhadd(DataTypeValue::U8, dst, lhs, rhs)
    346           : __ Vhadd(DataTypeValue::U8, dst, lhs, rhs);
    347       break;
    348     case DataType::Type::kInt8:
    349       DCHECK_EQ(8u, instruction->GetVectorLength());
    350       instruction->IsRounded()
    351           ? __ Vrhadd(DataTypeValue::S8, dst, lhs, rhs)
    352           : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs);
    353       break;
    354     case DataType::Type::kUint16:
    355       DCHECK_EQ(4u, instruction->GetVectorLength());
    356       instruction->IsRounded()
    357           ? __ Vrhadd(DataTypeValue::U16, dst, lhs, rhs)
    358           : __ Vhadd(DataTypeValue::U16, dst, lhs, rhs);
    359       break;
    360     case DataType::Type::kInt16:
    361       DCHECK_EQ(4u, instruction->GetVectorLength());
    362       instruction->IsRounded()
    363           ? __ Vrhadd(DataTypeValue::S16, dst, lhs, rhs)
    364           : __ Vhadd(DataTypeValue::S16, dst, lhs, rhs);
    365       break;
    366     default:
    367       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    368       UNREACHABLE();
    369   }
    370 }
    371 
    372 void LocationsBuilderARMVIXL::VisitVecSub(HVecSub* instruction) {
    373   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    374 }
    375 
    376 void InstructionCodeGeneratorARMVIXL::VisitVecSub(HVecSub* instruction) {
    377   LocationSummary* locations = instruction->GetLocations();
    378   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    379   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    380   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    381   switch (instruction->GetPackedType()) {
    382     case DataType::Type::kUint8:
    383     case DataType::Type::kInt8:
    384       DCHECK_EQ(8u, instruction->GetVectorLength());
    385       __ Vsub(I8, dst, lhs, rhs);
    386       break;
    387     case DataType::Type::kUint16:
    388     case DataType::Type::kInt16:
    389       DCHECK_EQ(4u, instruction->GetVectorLength());
    390       __ Vsub(I16, dst, lhs, rhs);
    391       break;
    392     case DataType::Type::kInt32:
    393       DCHECK_EQ(2u, instruction->GetVectorLength());
    394       __ Vsub(I32, dst, lhs, rhs);
    395       break;
    396     default:
    397       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    398       UNREACHABLE();
    399   }
    400 }
    401 
    402 void LocationsBuilderARMVIXL::VisitVecSaturationSub(HVecSaturationSub* instruction) {
    403   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    404 }
    405 
    406 void InstructionCodeGeneratorARMVIXL::VisitVecSaturationSub(HVecSaturationSub* instruction) {
    407   LocationSummary* locations = instruction->GetLocations();
    408   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    409   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    410   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    411   switch (instruction->GetPackedType()) {
    412     case DataType::Type::kUint8:
    413       DCHECK_EQ(8u, instruction->GetVectorLength());
    414       __ Vqsub(DataTypeValue::U8, dst, lhs, rhs);
    415       break;
    416     case DataType::Type::kInt8:
    417       DCHECK_EQ(8u, instruction->GetVectorLength());
    418       __ Vqsub(DataTypeValue::S8, dst, lhs, rhs);
    419       break;
    420     case DataType::Type::kUint16:
    421       DCHECK_EQ(4u, instruction->GetVectorLength());
    422       __ Vqsub(DataTypeValue::U16, dst, lhs, rhs);
    423       break;
    424     case DataType::Type::kInt16:
    425       DCHECK_EQ(4u, instruction->GetVectorLength());
    426       __ Vqsub(DataTypeValue::S16, dst, lhs, rhs);
    427       break;
    428     default:
    429       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    430       UNREACHABLE();
    431   }
    432 }
    433 
    434 void LocationsBuilderARMVIXL::VisitVecMul(HVecMul* instruction) {
    435   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    436 }
    437 
    438 void InstructionCodeGeneratorARMVIXL::VisitVecMul(HVecMul* instruction) {
    439   LocationSummary* locations = instruction->GetLocations();
    440   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    441   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    442   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    443   switch (instruction->GetPackedType()) {
    444     case DataType::Type::kUint8:
    445     case DataType::Type::kInt8:
    446       DCHECK_EQ(8u, instruction->GetVectorLength());
    447       __ Vmul(I8, dst, lhs, rhs);
    448       break;
    449     case DataType::Type::kUint16:
    450     case DataType::Type::kInt16:
    451       DCHECK_EQ(4u, instruction->GetVectorLength());
    452       __ Vmul(I16, dst, lhs, rhs);
    453       break;
    454     case DataType::Type::kInt32:
    455       DCHECK_EQ(2u, instruction->GetVectorLength());
    456       __ Vmul(I32, dst, lhs, rhs);
    457       break;
    458     default:
    459       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    460       UNREACHABLE();
    461   }
    462 }
    463 
    464 void LocationsBuilderARMVIXL::VisitVecDiv(HVecDiv* instruction) {
    465   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    466 }
    467 
    468 void InstructionCodeGeneratorARMVIXL::VisitVecDiv(HVecDiv* instruction) {
    469   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    470 }
    471 
    472 void LocationsBuilderARMVIXL::VisitVecMin(HVecMin* instruction) {
    473   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    474 }
    475 
    476 void InstructionCodeGeneratorARMVIXL::VisitVecMin(HVecMin* instruction) {
    477   LocationSummary* locations = instruction->GetLocations();
    478   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    479   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    480   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    481   switch (instruction->GetPackedType()) {
    482     case DataType::Type::kUint8:
    483       DCHECK_EQ(8u, instruction->GetVectorLength());
    484       __ Vmin(DataTypeValue::U8, dst, lhs, rhs);
    485       break;
    486     case DataType::Type::kInt8:
    487       DCHECK_EQ(8u, instruction->GetVectorLength());
    488       __ Vmin(DataTypeValue::S8, dst, lhs, rhs);
    489       break;
    490     case DataType::Type::kUint16:
    491       DCHECK_EQ(4u, instruction->GetVectorLength());
    492       __ Vmin(DataTypeValue::U16, dst, lhs, rhs);
    493       break;
    494     case DataType::Type::kInt16:
    495       DCHECK_EQ(4u, instruction->GetVectorLength());
    496       __ Vmin(DataTypeValue::S16, dst, lhs, rhs);
    497       break;
    498     case DataType::Type::kUint32:
    499       DCHECK_EQ(2u, instruction->GetVectorLength());
    500       __ Vmin(DataTypeValue::U32, dst, lhs, rhs);
    501       break;
    502     case DataType::Type::kInt32:
    503       DCHECK_EQ(2u, instruction->GetVectorLength());
    504       __ Vmin(DataTypeValue::S32, dst, lhs, rhs);
    505       break;
    506     default:
    507       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    508       UNREACHABLE();
    509   }
    510 }
    511 
    512 void LocationsBuilderARMVIXL::VisitVecMax(HVecMax* instruction) {
    513   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    514 }
    515 
    516 void InstructionCodeGeneratorARMVIXL::VisitVecMax(HVecMax* instruction) {
    517   LocationSummary* locations = instruction->GetLocations();
    518   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    519   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    520   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    521   switch (instruction->GetPackedType()) {
    522     case DataType::Type::kUint8:
    523       DCHECK_EQ(8u, instruction->GetVectorLength());
    524       __ Vmax(DataTypeValue::U8, dst, lhs, rhs);
    525       break;
    526     case DataType::Type::kInt8:
    527       DCHECK_EQ(8u, instruction->GetVectorLength());
    528       __ Vmax(DataTypeValue::S8, dst, lhs, rhs);
    529       break;
    530     case DataType::Type::kUint16:
    531       DCHECK_EQ(4u, instruction->GetVectorLength());
    532       __ Vmax(DataTypeValue::U16, dst, lhs, rhs);
    533       break;
    534     case DataType::Type::kInt16:
    535       DCHECK_EQ(4u, instruction->GetVectorLength());
    536       __ Vmax(DataTypeValue::S16, dst, lhs, rhs);
    537       break;
    538     case DataType::Type::kUint32:
    539       DCHECK_EQ(2u, instruction->GetVectorLength());
    540       __ Vmax(DataTypeValue::U32, dst, lhs, rhs);
    541       break;
    542     case DataType::Type::kInt32:
    543       DCHECK_EQ(2u, instruction->GetVectorLength());
    544       __ Vmax(DataTypeValue::S32, dst, lhs, rhs);
    545       break;
    546     default:
    547       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    548       UNREACHABLE();
    549   }
    550 }
    551 
    552 void LocationsBuilderARMVIXL::VisitVecAnd(HVecAnd* instruction) {
    553   // TODO: Allow constants supported by VAND (immediate).
    554   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    555 }
    556 
    557 void InstructionCodeGeneratorARMVIXL::VisitVecAnd(HVecAnd* instruction) {
    558   LocationSummary* locations = instruction->GetLocations();
    559   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    560   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    561   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    562   switch (instruction->GetPackedType()) {
    563     case DataType::Type::kBool:
    564     case DataType::Type::kUint8:
    565     case DataType::Type::kInt8:
    566     case DataType::Type::kUint16:
    567     case DataType::Type::kInt16:
    568     case DataType::Type::kInt32:
    569       __ Vand(I8, dst, lhs, rhs);
    570       break;
    571     default:
    572       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    573       UNREACHABLE();
    574   }
    575 }
    576 
    577 void LocationsBuilderARMVIXL::VisitVecAndNot(HVecAndNot* instruction) {
    578   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    579 }
    580 
    581 void InstructionCodeGeneratorARMVIXL::VisitVecAndNot(HVecAndNot* instruction) {
    582   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    583 }
    584 
    585 void LocationsBuilderARMVIXL::VisitVecOr(HVecOr* instruction) {
    586   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    587 }
    588 
    589 void InstructionCodeGeneratorARMVIXL::VisitVecOr(HVecOr* instruction) {
    590   LocationSummary* locations = instruction->GetLocations();
    591   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    592   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    593   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    594   switch (instruction->GetPackedType()) {
    595     case DataType::Type::kBool:
    596     case DataType::Type::kUint8:
    597     case DataType::Type::kInt8:
    598     case DataType::Type::kUint16:
    599     case DataType::Type::kInt16:
    600     case DataType::Type::kInt32:
    601       __ Vorr(I8, dst, lhs, rhs);
    602       break;
    603     default:
    604       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    605       UNREACHABLE();
    606   }
    607 }
    608 
    609 void LocationsBuilderARMVIXL::VisitVecXor(HVecXor* instruction) {
    610   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    611 }
    612 
    613 void InstructionCodeGeneratorARMVIXL::VisitVecXor(HVecXor* instruction) {
    614   LocationSummary* locations = instruction->GetLocations();
    615   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    616   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    617   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    618   switch (instruction->GetPackedType()) {
    619     case DataType::Type::kBool:
    620     case DataType::Type::kUint8:
    621     case DataType::Type::kInt8:
    622     case DataType::Type::kUint16:
    623     case DataType::Type::kInt16:
    624     case DataType::Type::kInt32:
    625       __ Veor(I8, dst, lhs, rhs);
    626       break;
    627     default:
    628       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    629       UNREACHABLE();
    630   }
    631 }
    632 
    633 // Helper to set up locations for vector shift operations.
    634 static void CreateVecShiftLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
    635   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    636   switch (instruction->GetPackedType()) {
    637     case DataType::Type::kUint8:
    638     case DataType::Type::kInt8:
    639     case DataType::Type::kUint16:
    640     case DataType::Type::kInt16:
    641     case DataType::Type::kInt32:
    642       locations->SetInAt(0, Location::RequiresFpuRegister());
    643       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
    644       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    645       break;
    646     default:
    647       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    648       UNREACHABLE();
    649   }
    650 }
    651 
    652 void LocationsBuilderARMVIXL::VisitVecShl(HVecShl* instruction) {
    653   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    654 }
    655 
    656 void InstructionCodeGeneratorARMVIXL::VisitVecShl(HVecShl* instruction) {
    657   LocationSummary* locations = instruction->GetLocations();
    658   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    659   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    660   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    661   switch (instruction->GetPackedType()) {
    662     case DataType::Type::kUint8:
    663     case DataType::Type::kInt8:
    664       DCHECK_EQ(8u, instruction->GetVectorLength());
    665       __ Vshl(I8, dst, lhs, value);
    666       break;
    667     case DataType::Type::kUint16:
    668     case DataType::Type::kInt16:
    669       DCHECK_EQ(4u, instruction->GetVectorLength());
    670       __ Vshl(I16, dst, lhs, value);
    671       break;
    672     case DataType::Type::kInt32:
    673       DCHECK_EQ(2u, instruction->GetVectorLength());
    674       __ Vshl(I32, dst, lhs, value);
    675       break;
    676     default:
    677       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    678       UNREACHABLE();
    679   }
    680 }
    681 
    682 void LocationsBuilderARMVIXL::VisitVecShr(HVecShr* instruction) {
    683   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    684 }
    685 
    686 void InstructionCodeGeneratorARMVIXL::VisitVecShr(HVecShr* instruction) {
    687   LocationSummary* locations = instruction->GetLocations();
    688   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    689   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    690   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    691   switch (instruction->GetPackedType()) {
    692     case DataType::Type::kUint8:
    693     case DataType::Type::kInt8:
    694       DCHECK_EQ(8u, instruction->GetVectorLength());
    695       __ Vshr(DataTypeValue::S8, dst, lhs, value);
    696       break;
    697     case DataType::Type::kUint16:
    698     case DataType::Type::kInt16:
    699       DCHECK_EQ(4u, instruction->GetVectorLength());
    700       __ Vshr(DataTypeValue::S16, dst, lhs, value);
    701       break;
    702     case DataType::Type::kInt32:
    703       DCHECK_EQ(2u, instruction->GetVectorLength());
    704       __ Vshr(DataTypeValue::S32, dst, lhs, value);
    705       break;
    706     default:
    707       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    708       UNREACHABLE();
    709   }
    710 }
    711 
    712 void LocationsBuilderARMVIXL::VisitVecUShr(HVecUShr* instruction) {
    713   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    714 }
    715 
    716 void InstructionCodeGeneratorARMVIXL::VisitVecUShr(HVecUShr* instruction) {
    717   LocationSummary* locations = instruction->GetLocations();
    718   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    719   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    720   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    721   switch (instruction->GetPackedType()) {
    722     case DataType::Type::kUint8:
    723     case DataType::Type::kInt8:
    724       DCHECK_EQ(8u, instruction->GetVectorLength());
    725       __ Vshr(DataTypeValue::U8, dst, lhs, value);
    726       break;
    727     case DataType::Type::kUint16:
    728     case DataType::Type::kInt16:
    729       DCHECK_EQ(4u, instruction->GetVectorLength());
    730       __ Vshr(DataTypeValue::U16, dst, lhs, value);
    731       break;
    732     case DataType::Type::kInt32:
    733       DCHECK_EQ(2u, instruction->GetVectorLength());
    734       __ Vshr(DataTypeValue::U32, dst, lhs, value);
    735       break;
    736     default:
    737       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    738       UNREACHABLE();
    739   }
    740 }
    741 
    742 void LocationsBuilderARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
    743   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
    744 
    745   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
    746 
    747   HInstruction* input = instruction->InputAt(0);
    748   bool is_zero = IsZeroBitPattern(input);
    749 
    750   switch (instruction->GetPackedType()) {
    751     case DataType::Type::kInt32:
    752       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
    753                                     : Location::RequiresRegister());
    754       locations->SetOut(Location::RequiresFpuRegister());
    755       break;
    756     default:
    757       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    758       UNREACHABLE();
    759   }
    760 }
    761 
    762 void InstructionCodeGeneratorARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
    763   LocationSummary* locations = instruction->GetLocations();
    764   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    765 
    766   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
    767 
    768   // Zero out all other elements first.
    769   __ Vmov(I32, dst, 0);
    770 
    771   // Shorthand for any type of zero.
    772   if (IsZeroBitPattern(instruction->InputAt(0))) {
    773     return;
    774   }
    775 
    776   // Set required elements.
    777   switch (instruction->GetPackedType()) {
    778     case DataType::Type::kInt32:
    779       DCHECK_EQ(2u, instruction->GetVectorLength());
    780       __ Vmov(Untyped32, DRegisterLane(dst, 0), InputRegisterAt(instruction, 0));
    781       break;
    782     default:
    783       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    784       UNREACHABLE();
    785   }
    786 }
    787 
    788 // Helper to set up locations for vector accumulations.
    789 static void CreateVecAccumLocations(ArenaAllocator* allocator, HVecOperation* instruction) {
    790   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    791   switch (instruction->GetPackedType()) {
    792     case DataType::Type::kUint8:
    793     case DataType::Type::kInt8:
    794     case DataType::Type::kUint16:
    795     case DataType::Type::kInt16:
    796     case DataType::Type::kInt32:
    797     case DataType::Type::kInt64:
    798       locations->SetInAt(0, Location::RequiresFpuRegister());
    799       locations->SetInAt(1, Location::RequiresFpuRegister());
    800       locations->SetInAt(2, Location::RequiresFpuRegister());
    801       locations->SetOut(Location::SameAsFirstInput());
    802       break;
    803     default:
    804       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    805       UNREACHABLE();
    806   }
    807 }
    808 
    809 void LocationsBuilderARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
    810   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
    811 }
    812 
    813 void InstructionCodeGeneratorARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
    814   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    815 }
    816 
    817 void LocationsBuilderARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
    818   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
    819 }
    820 
    821 void InstructionCodeGeneratorARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
    822   LocationSummary* locations = instruction->GetLocations();
    823   vixl32::DRegister acc = DRegisterFrom(locations->InAt(0));
    824   vixl32::DRegister left = DRegisterFrom(locations->InAt(1));
    825   vixl32::DRegister right = DRegisterFrom(locations->InAt(2));
    826 
    827   DCHECK(locations->InAt(0).Equals(locations->Out()));
    828 
    829   // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
    830   HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
    831   HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
    832   DCHECK_EQ(a->GetPackedType(), b->GetPackedType());
    833   switch (a->GetPackedType()) {
    834     case DataType::Type::kInt32:
    835       DCHECK_EQ(2u, a->GetVectorLength());
    836       switch (instruction->GetPackedType()) {
    837         case DataType::Type::kInt32: {
    838           DCHECK_EQ(2u, instruction->GetVectorLength());
    839           UseScratchRegisterScope temps(GetVIXLAssembler());
    840           vixl32::DRegister tmp = temps.AcquireD();
    841           __ Vsub(DataTypeValue::I32, tmp, left, right);
    842           __ Vabs(DataTypeValue::S32, tmp, tmp);
    843           __ Vadd(DataTypeValue::I32, acc, acc, tmp);
    844           break;
    845         }
    846         default:
    847           LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    848           UNREACHABLE();
    849       }
    850       break;
    851     default:
    852       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    853       UNREACHABLE();
    854   }
    855 }
    856 
    857 void LocationsBuilderARMVIXL::VisitVecDotProd(HVecDotProd* instruction) {
    858   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    859 }
    860 
    861 void InstructionCodeGeneratorARMVIXL::VisitVecDotProd(HVecDotProd* instruction) {
    862   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    863 }
    864 
    865 // Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word
    866 // size equals to 4).
    867 static bool IsWordAligned(HVecMemoryOperation* instruction) {
    868   return instruction->GetAlignment().IsAlignedAt(4u);
    869 }
    870 
    871 // Helper to set up locations for vector memory operations.
    872 static void CreateVecMemLocations(ArenaAllocator* allocator,
    873                                   HVecMemoryOperation* instruction,
    874                                   bool is_load) {
    875   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    876   switch (instruction->GetPackedType()) {
    877     case DataType::Type::kBool:
    878     case DataType::Type::kUint8:
    879     case DataType::Type::kInt8:
    880     case DataType::Type::kUint16:
    881     case DataType::Type::kInt16:
    882     case DataType::Type::kInt32:
    883       locations->SetInAt(0, Location::RequiresRegister());
    884       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
    885       if (is_load) {
    886         locations->SetOut(Location::RequiresFpuRegister());
    887       } else {
    888         locations->SetInAt(2, Location::RequiresFpuRegister());
    889       }
    890       break;
    891     default:
    892       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    893       UNREACHABLE();
    894   }
    895 }
    896 
    897 // Helper to set up locations for vector memory operations. Returns the memory operand and,
    898 // if used, sets the output parameter scratch to a temporary register used in this operand,
    899 // so that the client can release it right after the memory operand use.
    900 MemOperand InstructionCodeGeneratorARMVIXL::VecAddress(
    901         HVecMemoryOperation* instruction,
    902         UseScratchRegisterScope* temps_scope,
    903         /*out*/ vixl32::Register* scratch) {
    904   LocationSummary* locations = instruction->GetLocations();
    905   vixl32::Register base = InputRegisterAt(instruction, 0);
    906 
    907   Location index = locations->InAt(1);
    908   size_t size = DataType::Size(instruction->GetPackedType());
    909   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
    910   size_t shift = ComponentSizeShiftWidth(size);
    911 
    912   // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
    913   DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
    914 
    915   if (index.IsConstant()) {
    916     offset += Int64ConstantFrom(index) << shift;
    917     return MemOperand(base, offset);
    918   } else {
    919     *scratch = temps_scope->Acquire();
    920     __ Add(*scratch, base, Operand(RegisterFrom(index), ShiftType::LSL, shift));
    921 
    922     return MemOperand(*scratch, offset);
    923   }
    924 }
    925 
    926 AlignedMemOperand InstructionCodeGeneratorARMVIXL::VecAddressUnaligned(
    927         HVecMemoryOperation* instruction,
    928         UseScratchRegisterScope* temps_scope,
    929         /*out*/ vixl32::Register* scratch) {
    930   LocationSummary* locations = instruction->GetLocations();
    931   vixl32::Register base = InputRegisterAt(instruction, 0);
    932 
    933   Location index = locations->InAt(1);
    934   size_t size = DataType::Size(instruction->GetPackedType());
    935   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
    936   size_t shift = ComponentSizeShiftWidth(size);
    937 
    938   // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
    939   DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
    940 
    941   if (index.IsConstant()) {
    942     offset += Int64ConstantFrom(index) << shift;
    943     __ Add(*scratch, base, offset);
    944   } else {
    945     *scratch = temps_scope->Acquire();
    946     __ Add(*scratch, base, offset);
    947     __ Add(*scratch, *scratch, Operand(RegisterFrom(index), ShiftType::LSL, shift));
    948   }
    949   return AlignedMemOperand(*scratch, kNoAlignment);
    950 }
    951 
    952 void LocationsBuilderARMVIXL::VisitVecLoad(HVecLoad* instruction) {
    953   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /*is_load*/ true);
    954 }
    955 
    956 void InstructionCodeGeneratorARMVIXL::VisitVecLoad(HVecLoad* instruction) {
    957   vixl32::DRegister reg = OutputDRegister(instruction);
    958   UseScratchRegisterScope temps(GetVIXLAssembler());
    959   vixl32::Register scratch;
    960 
    961   DCHECK(instruction->GetPackedType() != DataType::Type::kUint16 || !instruction->IsStringCharAt());
    962 
    963   switch (instruction->GetPackedType()) {
    964     case DataType::Type::kBool:
    965     case DataType::Type::kUint8:
    966     case DataType::Type::kInt8:
    967       DCHECK_EQ(8u, instruction->GetVectorLength());
    968       if (IsWordAligned(instruction)) {
    969         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    970       } else {
    971         __ Vld1(Untyped8,
    972             NeonRegisterList(reg, kMultipleLanes),
    973             VecAddressUnaligned(instruction, &temps, &scratch));
    974       }
    975       break;
    976     case DataType::Type::kUint16:
    977     case DataType::Type::kInt16:
    978       DCHECK_EQ(4u, instruction->GetVectorLength());
    979       if (IsWordAligned(instruction)) {
    980         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    981       } else {
    982         __ Vld1(Untyped16,
    983             NeonRegisterList(reg, kMultipleLanes),
    984             VecAddressUnaligned(instruction, &temps, &scratch));
    985       }
    986       break;
    987     case DataType::Type::kInt32:
    988       DCHECK_EQ(2u, instruction->GetVectorLength());
    989       if (IsWordAligned(instruction)) {
    990         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    991       } else {
    992         __ Vld1(Untyped32,
    993             NeonRegisterList(reg, kMultipleLanes),
    994             VecAddressUnaligned(instruction, &temps, &scratch));
    995       }
    996       break;
    997     default:
    998       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
    999       UNREACHABLE();
   1000   }
   1001 }
   1002 
   1003 void LocationsBuilderARMVIXL::VisitVecStore(HVecStore* instruction) {
   1004   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /*is_load*/ false);
   1005 }
   1006 
   1007 void InstructionCodeGeneratorARMVIXL::VisitVecStore(HVecStore* instruction) {
   1008   vixl32::DRegister reg = InputDRegisterAt(instruction, 2);
   1009   UseScratchRegisterScope temps(GetVIXLAssembler());
   1010   vixl32::Register scratch;
   1011   switch (instruction->GetPackedType()) {
   1012     case DataType::Type::kBool:
   1013     case DataType::Type::kUint8:
   1014     case DataType::Type::kInt8:
   1015       DCHECK_EQ(8u, instruction->GetVectorLength());
   1016       if (IsWordAligned(instruction)) {
   1017         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
   1018       } else {
   1019         __ Vst1(Untyped8,
   1020                 NeonRegisterList(reg, kMultipleLanes),
   1021                 VecAddressUnaligned(instruction, &temps, &scratch));
   1022       }
   1023       break;
   1024     case DataType::Type::kUint16:
   1025     case DataType::Type::kInt16:
   1026       DCHECK_EQ(4u, instruction->GetVectorLength());
   1027       if (IsWordAligned(instruction)) {
   1028         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
   1029       } else {
   1030         __ Vst1(Untyped16,
   1031                 NeonRegisterList(reg, kMultipleLanes),
   1032                 VecAddressUnaligned(instruction, &temps, &scratch));
   1033       }
   1034       break;
   1035     case DataType::Type::kInt32:
   1036       DCHECK_EQ(2u, instruction->GetVectorLength());
   1037       if (IsWordAligned(instruction)) {
   1038         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
   1039       } else {
   1040         __ Vst1(Untyped32,
   1041                 NeonRegisterList(reg, kMultipleLanes),
   1042                 VecAddressUnaligned(instruction, &temps, &scratch));
   1043       }
   1044       break;
   1045     default:
   1046       LOG(FATAL) << "Unsupported SIMD type: " << instruction->GetPackedType();
   1047       UNREACHABLE();
   1048   }
   1049 }
   1050 
   1051 #undef __
   1052 
   1053 }  // namespace arm
   1054 }  // namespace art
   1055