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::RegisterFrom;
     32 
     33 #define __ GetVIXLAssembler()->
     34 
     35 void LocationsBuilderARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
     36   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
     37   switch (instruction->GetPackedType()) {
     38     case Primitive::kPrimBoolean:
     39     case Primitive::kPrimByte:
     40     case Primitive::kPrimChar:
     41     case Primitive::kPrimShort:
     42     case Primitive::kPrimInt:
     43       locations->SetInAt(0, Location::RequiresRegister());
     44       locations->SetOut(Location::RequiresFpuRegister());
     45       break;
     46     default:
     47       LOG(FATAL) << "Unsupported SIMD type";
     48       UNREACHABLE();
     49   }
     50 }
     51 
     52 void InstructionCodeGeneratorARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
     53   LocationSummary* locations = instruction->GetLocations();
     54   vixl32::DRegister dst = DRegisterFrom(locations->Out());
     55   switch (instruction->GetPackedType()) {
     56     case Primitive::kPrimBoolean:
     57     case Primitive::kPrimByte:
     58       DCHECK_EQ(8u, instruction->GetVectorLength());
     59       __ Vdup(Untyped8, dst, InputRegisterAt(instruction, 0));
     60       break;
     61     case Primitive::kPrimChar:
     62     case Primitive::kPrimShort:
     63       DCHECK_EQ(4u, instruction->GetVectorLength());
     64       __ Vdup(Untyped16, dst, InputRegisterAt(instruction, 0));
     65       break;
     66     case Primitive::kPrimInt:
     67       DCHECK_EQ(2u, instruction->GetVectorLength());
     68       __ Vdup(Untyped32, dst, InputRegisterAt(instruction, 0));
     69       break;
     70     default:
     71       LOG(FATAL) << "Unsupported SIMD type";
     72       UNREACHABLE();
     73   }
     74 }
     75 
     76 void LocationsBuilderARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
     77   LOG(FATAL) << "No SIMD for " << instruction->GetId();
     78 }
     79 
     80 void InstructionCodeGeneratorARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
     81   LOG(FATAL) << "No SIMD for " << instruction->GetId();
     82 }
     83 
     84 void LocationsBuilderARMVIXL::VisitVecSumReduce(HVecSumReduce* instruction) {
     85   LOG(FATAL) << "No SIMD for " << instruction->GetId();
     86 }
     87 
     88 void InstructionCodeGeneratorARMVIXL::VisitVecSumReduce(HVecSumReduce* instruction) {
     89   LOG(FATAL) << "No SIMD for " << instruction->GetId();
     90 }
     91 
     92 // Helper to set up locations for vector unary operations.
     93 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) {
     94   LocationSummary* locations = new (arena) LocationSummary(instruction);
     95   switch (instruction->GetPackedType()) {
     96     case Primitive::kPrimBoolean:
     97       locations->SetInAt(0, Location::RequiresFpuRegister());
     98       locations->SetOut(Location::RequiresFpuRegister(),
     99                         instruction->IsVecNot() ? Location::kOutputOverlap
    100                                                 : Location::kNoOutputOverlap);
    101       break;
    102     case Primitive::kPrimByte:
    103     case Primitive::kPrimChar:
    104     case Primitive::kPrimShort:
    105     case Primitive::kPrimInt:
    106       locations->SetInAt(0, Location::RequiresFpuRegister());
    107       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    108       break;
    109     default:
    110       LOG(FATAL) << "Unsupported SIMD type";
    111       UNREACHABLE();
    112   }
    113 }
    114 
    115 void LocationsBuilderARMVIXL::VisitVecCnv(HVecCnv* instruction) {
    116   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    117 }
    118 
    119 void InstructionCodeGeneratorARMVIXL::VisitVecCnv(HVecCnv* instruction) {
    120   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    121 }
    122 
    123 void LocationsBuilderARMVIXL::VisitVecNeg(HVecNeg* instruction) {
    124   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    125 }
    126 
    127 void InstructionCodeGeneratorARMVIXL::VisitVecNeg(HVecNeg* instruction) {
    128   LocationSummary* locations = instruction->GetLocations();
    129   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
    130   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    131   switch (instruction->GetPackedType()) {
    132     case Primitive::kPrimByte:
    133       DCHECK_EQ(8u, instruction->GetVectorLength());
    134       __ Vneg(DataTypeValue::S8, dst, src);
    135       break;
    136     case Primitive::kPrimChar:
    137     case Primitive::kPrimShort:
    138       DCHECK_EQ(4u, instruction->GetVectorLength());
    139       __ Vneg(DataTypeValue::S16, dst, src);
    140       break;
    141     case Primitive::kPrimInt:
    142       DCHECK_EQ(2u, instruction->GetVectorLength());
    143       __ Vneg(DataTypeValue::S32, dst, src);
    144       break;
    145     default:
    146       LOG(FATAL) << "Unsupported SIMD type";
    147       UNREACHABLE();
    148   }
    149 }
    150 
    151 void LocationsBuilderARMVIXL::VisitVecAbs(HVecAbs* instruction) {
    152   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    153 }
    154 
    155 void InstructionCodeGeneratorARMVIXL::VisitVecAbs(HVecAbs* instruction) {
    156   LocationSummary* locations = instruction->GetLocations();
    157   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
    158   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    159   switch (instruction->GetPackedType()) {
    160     case Primitive::kPrimByte:
    161       DCHECK_EQ(8u, instruction->GetVectorLength());
    162       __ Vabs(DataTypeValue::S8, dst, src);
    163       break;
    164     case Primitive::kPrimChar:
    165     case Primitive::kPrimShort:
    166       DCHECK_EQ(4u, instruction->GetVectorLength());
    167       __ Vabs(DataTypeValue::S16, dst, src);
    168       break;
    169     case Primitive::kPrimInt:
    170       DCHECK_EQ(2u, instruction->GetVectorLength());
    171       __ Vabs(DataTypeValue::S32, dst, src);
    172       break;
    173     default:
    174       LOG(FATAL) << "Unsupported SIMD type";
    175       UNREACHABLE();
    176   }
    177 }
    178 
    179 void LocationsBuilderARMVIXL::VisitVecNot(HVecNot* instruction) {
    180   CreateVecUnOpLocations(GetGraph()->GetArena(), instruction);
    181 }
    182 
    183 void InstructionCodeGeneratorARMVIXL::VisitVecNot(HVecNot* instruction) {
    184   LocationSummary* locations = instruction->GetLocations();
    185   vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
    186   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    187   switch (instruction->GetPackedType()) {
    188     case Primitive::kPrimBoolean:  // special case boolean-not
    189       DCHECK_EQ(8u, instruction->GetVectorLength());
    190       __ Vmov(I8, dst, 1);
    191       __ Veor(dst, dst, src);
    192       break;
    193     case Primitive::kPrimByte:
    194     case Primitive::kPrimChar:
    195     case Primitive::kPrimShort:
    196     case Primitive::kPrimInt:
    197       __ Vmvn(I8, dst, src);  // lanes do not matter
    198       break;
    199     default:
    200       LOG(FATAL) << "Unsupported SIMD type";
    201       UNREACHABLE();
    202   }
    203 }
    204 
    205 // Helper to set up locations for vector binary operations.
    206 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
    207   LocationSummary* locations = new (arena) LocationSummary(instruction);
    208   switch (instruction->GetPackedType()) {
    209     case Primitive::kPrimBoolean:
    210     case Primitive::kPrimByte:
    211     case Primitive::kPrimChar:
    212     case Primitive::kPrimShort:
    213     case Primitive::kPrimInt:
    214       locations->SetInAt(0, Location::RequiresFpuRegister());
    215       locations->SetInAt(1, Location::RequiresFpuRegister());
    216       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    217       break;
    218     default:
    219       LOG(FATAL) << "Unsupported SIMD type";
    220       UNREACHABLE();
    221   }
    222 }
    223 
    224 void LocationsBuilderARMVIXL::VisitVecAdd(HVecAdd* instruction) {
    225   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    226 }
    227 
    228 void InstructionCodeGeneratorARMVIXL::VisitVecAdd(HVecAdd* instruction) {
    229   LocationSummary* locations = instruction->GetLocations();
    230   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    231   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    232   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    233   switch (instruction->GetPackedType()) {
    234     case Primitive::kPrimByte:
    235       DCHECK_EQ(8u, instruction->GetVectorLength());
    236       __ Vadd(I8, dst, lhs, rhs);
    237       break;
    238     case Primitive::kPrimChar:
    239     case Primitive::kPrimShort:
    240       DCHECK_EQ(4u, instruction->GetVectorLength());
    241       __ Vadd(I16, dst, lhs, rhs);
    242       break;
    243     case Primitive::kPrimInt:
    244       DCHECK_EQ(2u, instruction->GetVectorLength());
    245       __ Vadd(I32, dst, lhs, rhs);
    246       break;
    247     default:
    248       LOG(FATAL) << "Unsupported SIMD type";
    249       UNREACHABLE();
    250   }
    251 }
    252 
    253 void LocationsBuilderARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    254   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    255 }
    256 
    257 void InstructionCodeGeneratorARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    258   LocationSummary* locations = instruction->GetLocations();
    259   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    260   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    261   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    262   switch (instruction->GetPackedType()) {
    263     case Primitive::kPrimByte:
    264       DCHECK_EQ(8u, instruction->GetVectorLength());
    265       if (instruction->IsUnsigned()) {
    266         instruction->IsRounded()
    267             ? __ Vrhadd(DataTypeValue::U8, dst, lhs, rhs)
    268             : __ Vhadd(DataTypeValue::U8, dst, lhs, rhs);
    269       } else {
    270         instruction->IsRounded()
    271             ? __ Vrhadd(DataTypeValue::S8, dst, lhs, rhs)
    272             : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs);
    273       }
    274       break;
    275     case Primitive::kPrimChar:
    276     case Primitive::kPrimShort:
    277       DCHECK_EQ(4u, instruction->GetVectorLength());
    278       if (instruction->IsUnsigned()) {
    279         instruction->IsRounded()
    280             ? __ Vrhadd(DataTypeValue::U16, dst, lhs, rhs)
    281             : __ Vhadd(DataTypeValue::U16, dst, lhs, rhs);
    282       } else {
    283         instruction->IsRounded()
    284             ? __ Vrhadd(DataTypeValue::S16, dst, lhs, rhs)
    285             : __ Vhadd(DataTypeValue::S16, dst, lhs, rhs);
    286       }
    287       break;
    288     default:
    289       LOG(FATAL) << "Unsupported SIMD type";
    290       UNREACHABLE();
    291   }
    292 }
    293 
    294 void LocationsBuilderARMVIXL::VisitVecSub(HVecSub* instruction) {
    295   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    296 }
    297 
    298 void InstructionCodeGeneratorARMVIXL::VisitVecSub(HVecSub* instruction) {
    299   LocationSummary* locations = instruction->GetLocations();
    300   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    301   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    302   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    303   switch (instruction->GetPackedType()) {
    304     case Primitive::kPrimByte:
    305       DCHECK_EQ(8u, instruction->GetVectorLength());
    306       __ Vsub(I8, dst, lhs, rhs);
    307       break;
    308     case Primitive::kPrimChar:
    309     case Primitive::kPrimShort:
    310       DCHECK_EQ(4u, instruction->GetVectorLength());
    311       __ Vsub(I16, dst, lhs, rhs);
    312       break;
    313     case Primitive::kPrimInt:
    314       DCHECK_EQ(2u, instruction->GetVectorLength());
    315       __ Vsub(I32, dst, lhs, rhs);
    316       break;
    317     default:
    318       LOG(FATAL) << "Unsupported SIMD type";
    319       UNREACHABLE();
    320   }
    321 }
    322 
    323 void LocationsBuilderARMVIXL::VisitVecMul(HVecMul* instruction) {
    324   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    325 }
    326 
    327 void InstructionCodeGeneratorARMVIXL::VisitVecMul(HVecMul* instruction) {
    328   LocationSummary* locations = instruction->GetLocations();
    329   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    330   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    331   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    332   switch (instruction->GetPackedType()) {
    333     case Primitive::kPrimByte:
    334       DCHECK_EQ(8u, instruction->GetVectorLength());
    335       __ Vmul(I8, dst, lhs, rhs);
    336       break;
    337     case Primitive::kPrimChar:
    338     case Primitive::kPrimShort:
    339       DCHECK_EQ(4u, instruction->GetVectorLength());
    340       __ Vmul(I16, dst, lhs, rhs);
    341       break;
    342     case Primitive::kPrimInt:
    343       DCHECK_EQ(2u, instruction->GetVectorLength());
    344       __ Vmul(I32, dst, lhs, rhs);
    345       break;
    346     default:
    347       LOG(FATAL) << "Unsupported SIMD type";
    348       UNREACHABLE();
    349   }
    350 }
    351 
    352 void LocationsBuilderARMVIXL::VisitVecDiv(HVecDiv* instruction) {
    353   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    354 }
    355 
    356 void InstructionCodeGeneratorARMVIXL::VisitVecDiv(HVecDiv* instruction) {
    357   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    358 }
    359 
    360 void LocationsBuilderARMVIXL::VisitVecMin(HVecMin* instruction) {
    361   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    362 }
    363 
    364 void InstructionCodeGeneratorARMVIXL::VisitVecMin(HVecMin* instruction) {
    365   LocationSummary* locations = instruction->GetLocations();
    366   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    367   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    368   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    369   switch (instruction->GetPackedType()) {
    370     case Primitive::kPrimByte:
    371       DCHECK_EQ(8u, instruction->GetVectorLength());
    372       if (instruction->IsUnsigned()) {
    373         __ Vmin(DataTypeValue::U8, dst, lhs, rhs);
    374       } else {
    375         __ Vmin(DataTypeValue::S8, dst, lhs, rhs);
    376       }
    377       break;
    378     case Primitive::kPrimChar:
    379     case Primitive::kPrimShort:
    380       DCHECK_EQ(4u, instruction->GetVectorLength());
    381       if (instruction->IsUnsigned()) {
    382         __ Vmin(DataTypeValue::U16, dst, lhs, rhs);
    383       } else {
    384         __ Vmin(DataTypeValue::S16, dst, lhs, rhs);
    385       }
    386       break;
    387     case Primitive::kPrimInt:
    388       DCHECK_EQ(2u, instruction->GetVectorLength());
    389       if (instruction->IsUnsigned()) {
    390         __ Vmin(DataTypeValue::U32, dst, lhs, rhs);
    391       } else {
    392         __ Vmin(DataTypeValue::S32, dst, lhs, rhs);
    393       }
    394       break;
    395     default:
    396       LOG(FATAL) << "Unsupported SIMD type";
    397       UNREACHABLE();
    398   }
    399 }
    400 
    401 void LocationsBuilderARMVIXL::VisitVecMax(HVecMax* instruction) {
    402   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    403 }
    404 
    405 void InstructionCodeGeneratorARMVIXL::VisitVecMax(HVecMax* instruction) {
    406   LocationSummary* locations = instruction->GetLocations();
    407   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    408   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    409   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    410   switch (instruction->GetPackedType()) {
    411     case Primitive::kPrimByte:
    412       DCHECK_EQ(8u, instruction->GetVectorLength());
    413       if (instruction->IsUnsigned()) {
    414         __ Vmax(DataTypeValue::U8, dst, lhs, rhs);
    415       } else {
    416         __ Vmax(DataTypeValue::S8, dst, lhs, rhs);
    417       }
    418       break;
    419     case Primitive::kPrimChar:
    420     case Primitive::kPrimShort:
    421       DCHECK_EQ(4u, instruction->GetVectorLength());
    422       if (instruction->IsUnsigned()) {
    423         __ Vmax(DataTypeValue::U16, dst, lhs, rhs);
    424       } else {
    425         __ Vmax(DataTypeValue::S16, dst, lhs, rhs);
    426       }
    427       break;
    428     case Primitive::kPrimInt:
    429       DCHECK_EQ(2u, instruction->GetVectorLength());
    430       if (instruction->IsUnsigned()) {
    431         __ Vmax(DataTypeValue::U32, dst, lhs, rhs);
    432       } else {
    433         __ Vmax(DataTypeValue::S32, dst, lhs, rhs);
    434       }
    435       break;
    436     default:
    437       LOG(FATAL) << "Unsupported SIMD type";
    438       UNREACHABLE();
    439   }
    440 }
    441 
    442 void LocationsBuilderARMVIXL::VisitVecAnd(HVecAnd* instruction) {
    443   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    444 }
    445 
    446 void InstructionCodeGeneratorARMVIXL::VisitVecAnd(HVecAnd* instruction) {
    447   LocationSummary* locations = instruction->GetLocations();
    448   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    449   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    450   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    451   switch (instruction->GetPackedType()) {
    452     case Primitive::kPrimBoolean:
    453     case Primitive::kPrimByte:
    454     case Primitive::kPrimChar:
    455     case Primitive::kPrimShort:
    456     case Primitive::kPrimInt:
    457       __ Vand(I8, dst, lhs, rhs);
    458       break;
    459     default:
    460       LOG(FATAL) << "Unsupported SIMD type";
    461       UNREACHABLE();
    462   }
    463 }
    464 
    465 void LocationsBuilderARMVIXL::VisitVecAndNot(HVecAndNot* instruction) {
    466   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    467 }
    468 
    469 void InstructionCodeGeneratorARMVIXL::VisitVecAndNot(HVecAndNot* instruction) {
    470   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    471 }
    472 
    473 void LocationsBuilderARMVIXL::VisitVecOr(HVecOr* instruction) {
    474   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    475 }
    476 
    477 void InstructionCodeGeneratorARMVIXL::VisitVecOr(HVecOr* instruction) {
    478   LocationSummary* locations = instruction->GetLocations();
    479   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    480   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    481   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    482   switch (instruction->GetPackedType()) {
    483     case Primitive::kPrimBoolean:
    484     case Primitive::kPrimByte:
    485     case Primitive::kPrimChar:
    486     case Primitive::kPrimShort:
    487     case Primitive::kPrimInt:
    488       __ Vorr(I8, dst, lhs, rhs);
    489       break;
    490     default:
    491       LOG(FATAL) << "Unsupported SIMD type";
    492       UNREACHABLE();
    493   }
    494 }
    495 
    496 void LocationsBuilderARMVIXL::VisitVecXor(HVecXor* instruction) {
    497   CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
    498 }
    499 
    500 void InstructionCodeGeneratorARMVIXL::VisitVecXor(HVecXor* instruction) {
    501   LocationSummary* locations = instruction->GetLocations();
    502   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    503   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    504   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    505   switch (instruction->GetPackedType()) {
    506     case Primitive::kPrimBoolean:
    507     case Primitive::kPrimByte:
    508     case Primitive::kPrimChar:
    509     case Primitive::kPrimShort:
    510     case Primitive::kPrimInt:
    511       __ Veor(I8, dst, lhs, rhs);
    512       break;
    513     default:
    514       LOG(FATAL) << "Unsupported SIMD type";
    515       UNREACHABLE();
    516   }
    517 }
    518 
    519 // Helper to set up locations for vector shift operations.
    520 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
    521   LocationSummary* locations = new (arena) LocationSummary(instruction);
    522   switch (instruction->GetPackedType()) {
    523     case Primitive::kPrimByte:
    524     case Primitive::kPrimChar:
    525     case Primitive::kPrimShort:
    526     case Primitive::kPrimInt:
    527       locations->SetInAt(0, Location::RequiresFpuRegister());
    528       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
    529       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    530       break;
    531     default:
    532       LOG(FATAL) << "Unsupported SIMD type";
    533       UNREACHABLE();
    534   }
    535 }
    536 
    537 void LocationsBuilderARMVIXL::VisitVecShl(HVecShl* instruction) {
    538   CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
    539 }
    540 
    541 void InstructionCodeGeneratorARMVIXL::VisitVecShl(HVecShl* instruction) {
    542   LocationSummary* locations = instruction->GetLocations();
    543   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    544   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    545   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    546   switch (instruction->GetPackedType()) {
    547     case Primitive::kPrimByte:
    548       DCHECK_EQ(8u, instruction->GetVectorLength());
    549       __ Vshl(I8, dst, lhs, value);
    550       break;
    551     case Primitive::kPrimChar:
    552     case Primitive::kPrimShort:
    553       DCHECK_EQ(4u, instruction->GetVectorLength());
    554       __ Vshl(I16, dst, lhs, value);
    555       break;
    556     case Primitive::kPrimInt:
    557       DCHECK_EQ(2u, instruction->GetVectorLength());
    558       __ Vshl(I32, dst, lhs, value);
    559       break;
    560     default:
    561       LOG(FATAL) << "Unsupported SIMD type";
    562       UNREACHABLE();
    563   }
    564 }
    565 
    566 void LocationsBuilderARMVIXL::VisitVecShr(HVecShr* instruction) {
    567   CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
    568 }
    569 
    570 void InstructionCodeGeneratorARMVIXL::VisitVecShr(HVecShr* instruction) {
    571   LocationSummary* locations = instruction->GetLocations();
    572   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    573   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    574   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    575   switch (instruction->GetPackedType()) {
    576     case Primitive::kPrimByte:
    577       DCHECK_EQ(8u, instruction->GetVectorLength());
    578       __ Vshr(DataTypeValue::S8, dst, lhs, value);
    579       break;
    580     case Primitive::kPrimChar:
    581     case Primitive::kPrimShort:
    582       DCHECK_EQ(4u, instruction->GetVectorLength());
    583       __ Vshr(DataTypeValue::S16, dst, lhs, value);
    584       break;
    585     case Primitive::kPrimInt:
    586       DCHECK_EQ(2u, instruction->GetVectorLength());
    587       __ Vshr(DataTypeValue::S32, dst, lhs, value);
    588       break;
    589     default:
    590       LOG(FATAL) << "Unsupported SIMD type";
    591       UNREACHABLE();
    592   }
    593 }
    594 
    595 void LocationsBuilderARMVIXL::VisitVecUShr(HVecUShr* instruction) {
    596   CreateVecShiftLocations(GetGraph()->GetArena(), instruction);
    597 }
    598 
    599 void InstructionCodeGeneratorARMVIXL::VisitVecUShr(HVecUShr* instruction) {
    600   LocationSummary* locations = instruction->GetLocations();
    601   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    602   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    603   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    604   switch (instruction->GetPackedType()) {
    605     case Primitive::kPrimByte:
    606       DCHECK_EQ(8u, instruction->GetVectorLength());
    607       __ Vshr(DataTypeValue::U8, dst, lhs, value);
    608       break;
    609     case Primitive::kPrimChar:
    610     case Primitive::kPrimShort:
    611       DCHECK_EQ(4u, instruction->GetVectorLength());
    612       __ Vshr(DataTypeValue::U16, dst, lhs, value);
    613       break;
    614     case Primitive::kPrimInt:
    615       DCHECK_EQ(2u, instruction->GetVectorLength());
    616       __ Vshr(DataTypeValue::U32, dst, lhs, value);
    617       break;
    618     default:
    619       LOG(FATAL) << "Unsupported SIMD type";
    620       UNREACHABLE();
    621   }
    622 }
    623 
    624 void LocationsBuilderARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
    625   LOG(FATAL) << "No SIMD for " << instr->GetId();
    626 }
    627 
    628 void InstructionCodeGeneratorARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
    629   LOG(FATAL) << "No SIMD for " << instr->GetId();
    630 }
    631 
    632 // Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word
    633 // size equals to 4).
    634 static bool IsWordAligned(HVecMemoryOperation* instruction) {
    635   return instruction->GetAlignment().IsAlignedAt(4u);
    636 }
    637 
    638 // Helper to set up locations for vector memory operations.
    639 static void CreateVecMemLocations(ArenaAllocator* arena,
    640                                   HVecMemoryOperation* instruction,
    641                                   bool is_load) {
    642   LocationSummary* locations = new (arena) LocationSummary(instruction);
    643   switch (instruction->GetPackedType()) {
    644     case Primitive::kPrimBoolean:
    645     case Primitive::kPrimByte:
    646     case Primitive::kPrimChar:
    647     case Primitive::kPrimShort:
    648     case Primitive::kPrimInt:
    649       locations->SetInAt(0, Location::RequiresRegister());
    650       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
    651       if (is_load) {
    652         locations->SetOut(Location::RequiresFpuRegister());
    653       } else {
    654         locations->SetInAt(2, Location::RequiresFpuRegister());
    655       }
    656       break;
    657     default:
    658       LOG(FATAL) << "Unsupported SIMD type";
    659       UNREACHABLE();
    660   }
    661 }
    662 
    663 // Helper to set up locations for vector memory operations. Returns the memory operand and,
    664 // if used, sets the output parameter scratch to a temporary register used in this operand,
    665 // so that the client can release it right after the memory operand use.
    666 MemOperand InstructionCodeGeneratorARMVIXL::VecAddress(
    667         HVecMemoryOperation* instruction,
    668         UseScratchRegisterScope* temps_scope,
    669         /*out*/ vixl32::Register* scratch) {
    670   LocationSummary* locations = instruction->GetLocations();
    671   vixl32::Register base = InputRegisterAt(instruction, 0);
    672 
    673   Location index = locations->InAt(1);
    674   size_t size = Primitive::ComponentSize(instruction->GetPackedType());
    675   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
    676   size_t shift = ComponentSizeShiftWidth(size);
    677 
    678   // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
    679   DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
    680 
    681   if (index.IsConstant()) {
    682     offset += Int64ConstantFrom(index) << shift;
    683     return MemOperand(base, offset);
    684   } else {
    685     *scratch = temps_scope->Acquire();
    686     __ Add(*scratch, base, Operand(RegisterFrom(index), ShiftType::LSL, shift));
    687 
    688     return MemOperand(*scratch, offset);
    689   }
    690 }
    691 
    692 AlignedMemOperand InstructionCodeGeneratorARMVIXL::VecAddressUnaligned(
    693         HVecMemoryOperation* instruction,
    694         UseScratchRegisterScope* temps_scope,
    695         /*out*/ vixl32::Register* scratch) {
    696   LocationSummary* locations = instruction->GetLocations();
    697   vixl32::Register base = InputRegisterAt(instruction, 0);
    698 
    699   Location index = locations->InAt(1);
    700   size_t size = Primitive::ComponentSize(instruction->GetPackedType());
    701   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
    702   size_t shift = ComponentSizeShiftWidth(size);
    703 
    704   // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
    705   DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
    706 
    707   if (index.IsConstant()) {
    708     offset += Int64ConstantFrom(index) << shift;
    709     __ Add(*scratch, base, offset);
    710   } else {
    711     *scratch = temps_scope->Acquire();
    712     __ Add(*scratch, base, offset);
    713     __ Add(*scratch, *scratch, Operand(RegisterFrom(index), ShiftType::LSL, shift));
    714   }
    715   return AlignedMemOperand(*scratch, kNoAlignment);
    716 }
    717 
    718 void LocationsBuilderARMVIXL::VisitVecLoad(HVecLoad* instruction) {
    719   CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ true);
    720 }
    721 
    722 void InstructionCodeGeneratorARMVIXL::VisitVecLoad(HVecLoad* instruction) {
    723   vixl32::DRegister reg = OutputDRegister(instruction);
    724   UseScratchRegisterScope temps(GetVIXLAssembler());
    725   vixl32::Register scratch;
    726 
    727   DCHECK(instruction->GetPackedType() != Primitive::kPrimChar || !instruction->IsStringCharAt());
    728 
    729   switch (instruction->GetPackedType()) {
    730     case Primitive::kPrimBoolean:
    731     case Primitive::kPrimByte:
    732       DCHECK_EQ(8u, instruction->GetVectorLength());
    733       if (IsWordAligned(instruction)) {
    734         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    735       } else {
    736         __ Vld1(Untyped8,
    737             NeonRegisterList(reg, kMultipleLanes),
    738             VecAddressUnaligned(instruction, &temps, &scratch));
    739       }
    740       break;
    741     case Primitive::kPrimChar:
    742     case Primitive::kPrimShort:
    743       DCHECK_EQ(4u, instruction->GetVectorLength());
    744       if (IsWordAligned(instruction)) {
    745         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    746       } else {
    747         __ Vld1(Untyped16,
    748             NeonRegisterList(reg, kMultipleLanes),
    749             VecAddressUnaligned(instruction, &temps, &scratch));
    750       }
    751       break;
    752     case Primitive::kPrimInt:
    753       DCHECK_EQ(2u, instruction->GetVectorLength());
    754       if (IsWordAligned(instruction)) {
    755         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    756       } else {
    757         __ Vld1(Untyped32,
    758             NeonRegisterList(reg, kMultipleLanes),
    759             VecAddressUnaligned(instruction, &temps, &scratch));
    760       }
    761       break;
    762     default:
    763       LOG(FATAL) << "Unsupported SIMD type";
    764       UNREACHABLE();
    765   }
    766 }
    767 
    768 void LocationsBuilderARMVIXL::VisitVecStore(HVecStore* instruction) {
    769   CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ false);
    770 }
    771 
    772 void InstructionCodeGeneratorARMVIXL::VisitVecStore(HVecStore* instruction) {
    773   vixl32::DRegister reg = InputDRegisterAt(instruction, 2);
    774   UseScratchRegisterScope temps(GetVIXLAssembler());
    775   vixl32::Register scratch;
    776   switch (instruction->GetPackedType()) {
    777     case Primitive::kPrimBoolean:
    778     case Primitive::kPrimByte:
    779       DCHECK_EQ(8u, instruction->GetVectorLength());
    780       if (IsWordAligned(instruction)) {
    781         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
    782       } else {
    783         __ Vst1(Untyped8,
    784                 NeonRegisterList(reg, kMultipleLanes),
    785                 VecAddressUnaligned(instruction, &temps, &scratch));
    786       }
    787       break;
    788     case Primitive::kPrimChar:
    789     case Primitive::kPrimShort:
    790       DCHECK_EQ(4u, instruction->GetVectorLength());
    791       if (IsWordAligned(instruction)) {
    792         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
    793       } else {
    794         __ Vst1(Untyped16,
    795                 NeonRegisterList(reg, kMultipleLanes),
    796                 VecAddressUnaligned(instruction, &temps, &scratch));
    797       }
    798       break;
    799     case Primitive::kPrimInt:
    800       DCHECK_EQ(2u, instruction->GetVectorLength());
    801       if (IsWordAligned(instruction)) {
    802         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
    803       } else {
    804         __ Vst1(Untyped32,
    805                 NeonRegisterList(reg, kMultipleLanes),
    806                 VecAddressUnaligned(instruction, &temps, &scratch));
    807       }
    808       break;
    809     default:
    810       LOG(FATAL) << "Unsupported SIMD type";
    811       UNREACHABLE();
    812   }
    813 }
    814 
    815 #undef __
    816 
    817 }  // namespace arm
    818 }  // namespace art
    819