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";
     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";
     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";
     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";
    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";
    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->GetKind()) {
    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";
    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";
    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";
    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";
    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";
    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";
    296       UNREACHABLE();
    297   }
    298 }
    299 
    300 void LocationsBuilderARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
    301   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    302 }
    303 
    304 void InstructionCodeGeneratorARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* 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       instruction->IsRounded()
    313           ? __ Vrhadd(DataTypeValue::U8, dst, lhs, rhs)
    314           : __ Vhadd(DataTypeValue::U8, dst, lhs, rhs);
    315       break;
    316     case DataType::Type::kInt8:
    317       DCHECK_EQ(8u, instruction->GetVectorLength());
    318       instruction->IsRounded()
    319           ? __ Vrhadd(DataTypeValue::S8, dst, lhs, rhs)
    320           : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs);
    321       break;
    322     case DataType::Type::kUint16:
    323       DCHECK_EQ(4u, instruction->GetVectorLength());
    324       instruction->IsRounded()
    325           ? __ Vrhadd(DataTypeValue::U16, dst, lhs, rhs)
    326           : __ Vhadd(DataTypeValue::U16, dst, lhs, rhs);
    327       break;
    328     case DataType::Type::kInt16:
    329       DCHECK_EQ(4u, instruction->GetVectorLength());
    330       instruction->IsRounded()
    331           ? __ Vrhadd(DataTypeValue::S16, dst, lhs, rhs)
    332           : __ Vhadd(DataTypeValue::S16, dst, lhs, rhs);
    333       break;
    334     default:
    335       LOG(FATAL) << "Unsupported SIMD type";
    336       UNREACHABLE();
    337   }
    338 }
    339 
    340 void LocationsBuilderARMVIXL::VisitVecSub(HVecSub* instruction) {
    341   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    342 }
    343 
    344 void InstructionCodeGeneratorARMVIXL::VisitVecSub(HVecSub* instruction) {
    345   LocationSummary* locations = instruction->GetLocations();
    346   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    347   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    348   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    349   switch (instruction->GetPackedType()) {
    350     case DataType::Type::kUint8:
    351     case DataType::Type::kInt8:
    352       DCHECK_EQ(8u, instruction->GetVectorLength());
    353       __ Vsub(I8, dst, lhs, rhs);
    354       break;
    355     case DataType::Type::kUint16:
    356     case DataType::Type::kInt16:
    357       DCHECK_EQ(4u, instruction->GetVectorLength());
    358       __ Vsub(I16, dst, lhs, rhs);
    359       break;
    360     case DataType::Type::kInt32:
    361       DCHECK_EQ(2u, instruction->GetVectorLength());
    362       __ Vsub(I32, dst, lhs, rhs);
    363       break;
    364     default:
    365       LOG(FATAL) << "Unsupported SIMD type";
    366       UNREACHABLE();
    367   }
    368 }
    369 
    370 void LocationsBuilderARMVIXL::VisitVecMul(HVecMul* instruction) {
    371   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    372 }
    373 
    374 void InstructionCodeGeneratorARMVIXL::VisitVecMul(HVecMul* instruction) {
    375   LocationSummary* locations = instruction->GetLocations();
    376   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    377   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    378   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    379   switch (instruction->GetPackedType()) {
    380     case DataType::Type::kUint8:
    381     case DataType::Type::kInt8:
    382       DCHECK_EQ(8u, instruction->GetVectorLength());
    383       __ Vmul(I8, dst, lhs, rhs);
    384       break;
    385     case DataType::Type::kUint16:
    386     case DataType::Type::kInt16:
    387       DCHECK_EQ(4u, instruction->GetVectorLength());
    388       __ Vmul(I16, dst, lhs, rhs);
    389       break;
    390     case DataType::Type::kInt32:
    391       DCHECK_EQ(2u, instruction->GetVectorLength());
    392       __ Vmul(I32, dst, lhs, rhs);
    393       break;
    394     default:
    395       LOG(FATAL) << "Unsupported SIMD type";
    396       UNREACHABLE();
    397   }
    398 }
    399 
    400 void LocationsBuilderARMVIXL::VisitVecDiv(HVecDiv* instruction) {
    401   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    402 }
    403 
    404 void InstructionCodeGeneratorARMVIXL::VisitVecDiv(HVecDiv* instruction) {
    405   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    406 }
    407 
    408 void LocationsBuilderARMVIXL::VisitVecMin(HVecMin* instruction) {
    409   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    410 }
    411 
    412 void InstructionCodeGeneratorARMVIXL::VisitVecMin(HVecMin* instruction) {
    413   LocationSummary* locations = instruction->GetLocations();
    414   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    415   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    416   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    417   switch (instruction->GetPackedType()) {
    418     case DataType::Type::kUint8:
    419       DCHECK_EQ(8u, instruction->GetVectorLength());
    420       __ Vmin(DataTypeValue::U8, dst, lhs, rhs);
    421       break;
    422     case DataType::Type::kInt8:
    423       DCHECK_EQ(8u, instruction->GetVectorLength());
    424       __ Vmin(DataTypeValue::S8, dst, lhs, rhs);
    425       break;
    426     case DataType::Type::kUint16:
    427       DCHECK_EQ(4u, instruction->GetVectorLength());
    428       __ Vmin(DataTypeValue::U16, dst, lhs, rhs);
    429       break;
    430     case DataType::Type::kInt16:
    431       DCHECK_EQ(4u, instruction->GetVectorLength());
    432       __ Vmin(DataTypeValue::S16, dst, lhs, rhs);
    433       break;
    434     case DataType::Type::kUint32:
    435       DCHECK_EQ(2u, instruction->GetVectorLength());
    436       __ Vmin(DataTypeValue::U32, dst, lhs, rhs);
    437       break;
    438     case DataType::Type::kInt32:
    439       DCHECK_EQ(2u, instruction->GetVectorLength());
    440       __ Vmin(DataTypeValue::S32, dst, lhs, rhs);
    441       break;
    442     default:
    443       LOG(FATAL) << "Unsupported SIMD type";
    444       UNREACHABLE();
    445   }
    446 }
    447 
    448 void LocationsBuilderARMVIXL::VisitVecMax(HVecMax* instruction) {
    449   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    450 }
    451 
    452 void InstructionCodeGeneratorARMVIXL::VisitVecMax(HVecMax* instruction) {
    453   LocationSummary* locations = instruction->GetLocations();
    454   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    455   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    456   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    457   switch (instruction->GetPackedType()) {
    458     case DataType::Type::kUint8:
    459       DCHECK_EQ(8u, instruction->GetVectorLength());
    460       __ Vmax(DataTypeValue::U8, dst, lhs, rhs);
    461       break;
    462     case DataType::Type::kInt8:
    463       DCHECK_EQ(8u, instruction->GetVectorLength());
    464       __ Vmax(DataTypeValue::S8, dst, lhs, rhs);
    465       break;
    466     case DataType::Type::kUint16:
    467       DCHECK_EQ(4u, instruction->GetVectorLength());
    468       __ Vmax(DataTypeValue::U16, dst, lhs, rhs);
    469       break;
    470     case DataType::Type::kInt16:
    471       DCHECK_EQ(4u, instruction->GetVectorLength());
    472       __ Vmax(DataTypeValue::S16, dst, lhs, rhs);
    473       break;
    474     case DataType::Type::kUint32:
    475       DCHECK_EQ(2u, instruction->GetVectorLength());
    476       __ Vmax(DataTypeValue::U32, dst, lhs, rhs);
    477       break;
    478     case DataType::Type::kInt32:
    479       DCHECK_EQ(2u, instruction->GetVectorLength());
    480       __ Vmax(DataTypeValue::S32, dst, lhs, rhs);
    481       break;
    482     default:
    483       LOG(FATAL) << "Unsupported SIMD type";
    484       UNREACHABLE();
    485   }
    486 }
    487 
    488 void LocationsBuilderARMVIXL::VisitVecAnd(HVecAnd* instruction) {
    489   // TODO: Allow constants supported by VAND (immediate).
    490   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    491 }
    492 
    493 void InstructionCodeGeneratorARMVIXL::VisitVecAnd(HVecAnd* instruction) {
    494   LocationSummary* locations = instruction->GetLocations();
    495   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    496   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    497   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    498   switch (instruction->GetPackedType()) {
    499     case DataType::Type::kBool:
    500     case DataType::Type::kUint8:
    501     case DataType::Type::kInt8:
    502     case DataType::Type::kUint16:
    503     case DataType::Type::kInt16:
    504     case DataType::Type::kInt32:
    505       __ Vand(I8, dst, lhs, rhs);
    506       break;
    507     default:
    508       LOG(FATAL) << "Unsupported SIMD type";
    509       UNREACHABLE();
    510   }
    511 }
    512 
    513 void LocationsBuilderARMVIXL::VisitVecAndNot(HVecAndNot* instruction) {
    514   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    515 }
    516 
    517 void InstructionCodeGeneratorARMVIXL::VisitVecAndNot(HVecAndNot* instruction) {
    518   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    519 }
    520 
    521 void LocationsBuilderARMVIXL::VisitVecOr(HVecOr* instruction) {
    522   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    523 }
    524 
    525 void InstructionCodeGeneratorARMVIXL::VisitVecOr(HVecOr* instruction) {
    526   LocationSummary* locations = instruction->GetLocations();
    527   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    528   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    529   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    530   switch (instruction->GetPackedType()) {
    531     case DataType::Type::kBool:
    532     case DataType::Type::kUint8:
    533     case DataType::Type::kInt8:
    534     case DataType::Type::kUint16:
    535     case DataType::Type::kInt16:
    536     case DataType::Type::kInt32:
    537       __ Vorr(I8, dst, lhs, rhs);
    538       break;
    539     default:
    540       LOG(FATAL) << "Unsupported SIMD type";
    541       UNREACHABLE();
    542   }
    543 }
    544 
    545 void LocationsBuilderARMVIXL::VisitVecXor(HVecXor* instruction) {
    546   CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction);
    547 }
    548 
    549 void InstructionCodeGeneratorARMVIXL::VisitVecXor(HVecXor* instruction) {
    550   LocationSummary* locations = instruction->GetLocations();
    551   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    552   vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
    553   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    554   switch (instruction->GetPackedType()) {
    555     case DataType::Type::kBool:
    556     case DataType::Type::kUint8:
    557     case DataType::Type::kInt8:
    558     case DataType::Type::kUint16:
    559     case DataType::Type::kInt16:
    560     case DataType::Type::kInt32:
    561       __ Veor(I8, dst, lhs, rhs);
    562       break;
    563     default:
    564       LOG(FATAL) << "Unsupported SIMD type";
    565       UNREACHABLE();
    566   }
    567 }
    568 
    569 // Helper to set up locations for vector shift operations.
    570 static void CreateVecShiftLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) {
    571   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    572   switch (instruction->GetPackedType()) {
    573     case DataType::Type::kUint8:
    574     case DataType::Type::kInt8:
    575     case DataType::Type::kUint16:
    576     case DataType::Type::kInt16:
    577     case DataType::Type::kInt32:
    578       locations->SetInAt(0, Location::RequiresFpuRegister());
    579       locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
    580       locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
    581       break;
    582     default:
    583       LOG(FATAL) << "Unsupported SIMD type";
    584       UNREACHABLE();
    585   }
    586 }
    587 
    588 void LocationsBuilderARMVIXL::VisitVecShl(HVecShl* instruction) {
    589   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    590 }
    591 
    592 void InstructionCodeGeneratorARMVIXL::VisitVecShl(HVecShl* instruction) {
    593   LocationSummary* locations = instruction->GetLocations();
    594   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    595   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    596   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    597   switch (instruction->GetPackedType()) {
    598     case DataType::Type::kUint8:
    599     case DataType::Type::kInt8:
    600       DCHECK_EQ(8u, instruction->GetVectorLength());
    601       __ Vshl(I8, dst, lhs, value);
    602       break;
    603     case DataType::Type::kUint16:
    604     case DataType::Type::kInt16:
    605       DCHECK_EQ(4u, instruction->GetVectorLength());
    606       __ Vshl(I16, dst, lhs, value);
    607       break;
    608     case DataType::Type::kInt32:
    609       DCHECK_EQ(2u, instruction->GetVectorLength());
    610       __ Vshl(I32, dst, lhs, value);
    611       break;
    612     default:
    613       LOG(FATAL) << "Unsupported SIMD type";
    614       UNREACHABLE();
    615   }
    616 }
    617 
    618 void LocationsBuilderARMVIXL::VisitVecShr(HVecShr* instruction) {
    619   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    620 }
    621 
    622 void InstructionCodeGeneratorARMVIXL::VisitVecShr(HVecShr* instruction) {
    623   LocationSummary* locations = instruction->GetLocations();
    624   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    625   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    626   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    627   switch (instruction->GetPackedType()) {
    628     case DataType::Type::kUint8:
    629     case DataType::Type::kInt8:
    630       DCHECK_EQ(8u, instruction->GetVectorLength());
    631       __ Vshr(DataTypeValue::S8, dst, lhs, value);
    632       break;
    633     case DataType::Type::kUint16:
    634     case DataType::Type::kInt16:
    635       DCHECK_EQ(4u, instruction->GetVectorLength());
    636       __ Vshr(DataTypeValue::S16, dst, lhs, value);
    637       break;
    638     case DataType::Type::kInt32:
    639       DCHECK_EQ(2u, instruction->GetVectorLength());
    640       __ Vshr(DataTypeValue::S32, dst, lhs, value);
    641       break;
    642     default:
    643       LOG(FATAL) << "Unsupported SIMD type";
    644       UNREACHABLE();
    645   }
    646 }
    647 
    648 void LocationsBuilderARMVIXL::VisitVecUShr(HVecUShr* instruction) {
    649   CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction);
    650 }
    651 
    652 void InstructionCodeGeneratorARMVIXL::VisitVecUShr(HVecUShr* instruction) {
    653   LocationSummary* locations = instruction->GetLocations();
    654   vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
    655   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    656   int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
    657   switch (instruction->GetPackedType()) {
    658     case DataType::Type::kUint8:
    659     case DataType::Type::kInt8:
    660       DCHECK_EQ(8u, instruction->GetVectorLength());
    661       __ Vshr(DataTypeValue::U8, dst, lhs, value);
    662       break;
    663     case DataType::Type::kUint16:
    664     case DataType::Type::kInt16:
    665       DCHECK_EQ(4u, instruction->GetVectorLength());
    666       __ Vshr(DataTypeValue::U16, dst, lhs, value);
    667       break;
    668     case DataType::Type::kInt32:
    669       DCHECK_EQ(2u, instruction->GetVectorLength());
    670       __ Vshr(DataTypeValue::U32, dst, lhs, value);
    671       break;
    672     default:
    673       LOG(FATAL) << "Unsupported SIMD type";
    674       UNREACHABLE();
    675   }
    676 }
    677 
    678 void LocationsBuilderARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
    679   LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
    680 
    681   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
    682 
    683   HInstruction* input = instruction->InputAt(0);
    684   bool is_zero = IsZeroBitPattern(input);
    685 
    686   switch (instruction->GetPackedType()) {
    687     case DataType::Type::kInt32:
    688       locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant())
    689                                     : Location::RequiresRegister());
    690       locations->SetOut(Location::RequiresFpuRegister());
    691       break;
    692     default:
    693       LOG(FATAL) << "Unsupported SIMD type";
    694       UNREACHABLE();
    695   }
    696 }
    697 
    698 void InstructionCodeGeneratorARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
    699   LocationSummary* locations = instruction->GetLocations();
    700   vixl32::DRegister dst = DRegisterFrom(locations->Out());
    701 
    702   DCHECK_EQ(1u, instruction->InputCount());  // only one input currently implemented
    703 
    704   // Zero out all other elements first.
    705   __ Vmov(I32, dst, 0);
    706 
    707   // Shorthand for any type of zero.
    708   if (IsZeroBitPattern(instruction->InputAt(0))) {
    709     return;
    710   }
    711 
    712   // Set required elements.
    713   switch (instruction->GetPackedType()) {
    714     case DataType::Type::kInt32:
    715       DCHECK_EQ(2u, instruction->GetVectorLength());
    716       __ Vmov(Untyped32, DRegisterLane(dst, 0), InputRegisterAt(instruction, 0));
    717       break;
    718     default:
    719       LOG(FATAL) << "Unsupported SIMD type";
    720       UNREACHABLE();
    721   }
    722 }
    723 
    724 // Helper to set up locations for vector accumulations.
    725 static void CreateVecAccumLocations(ArenaAllocator* allocator, HVecOperation* instruction) {
    726   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    727   switch (instruction->GetPackedType()) {
    728     case DataType::Type::kUint8:
    729     case DataType::Type::kInt8:
    730     case DataType::Type::kUint16:
    731     case DataType::Type::kInt16:
    732     case DataType::Type::kInt32:
    733     case DataType::Type::kInt64:
    734       locations->SetInAt(0, Location::RequiresFpuRegister());
    735       locations->SetInAt(1, Location::RequiresFpuRegister());
    736       locations->SetInAt(2, Location::RequiresFpuRegister());
    737       locations->SetOut(Location::SameAsFirstInput());
    738       break;
    739     default:
    740       LOG(FATAL) << "Unsupported SIMD type";
    741       UNREACHABLE();
    742   }
    743 }
    744 
    745 void LocationsBuilderARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
    746   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
    747 }
    748 
    749 void InstructionCodeGeneratorARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) {
    750   LOG(FATAL) << "No SIMD for " << instruction->GetId();
    751 }
    752 
    753 void LocationsBuilderARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
    754   CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
    755 }
    756 
    757 void InstructionCodeGeneratorARMVIXL::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
    758   LocationSummary* locations = instruction->GetLocations();
    759   vixl32::DRegister acc = DRegisterFrom(locations->InAt(0));
    760   vixl32::DRegister left = DRegisterFrom(locations->InAt(1));
    761   vixl32::DRegister right = DRegisterFrom(locations->InAt(2));
    762 
    763   DCHECK(locations->InAt(0).Equals(locations->Out()));
    764 
    765   // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
    766   HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
    767   HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
    768   DCHECK_EQ(a->GetPackedType(), b->GetPackedType());
    769   switch (a->GetPackedType()) {
    770     case DataType::Type::kInt32:
    771       DCHECK_EQ(2u, a->GetVectorLength());
    772       switch (instruction->GetPackedType()) {
    773         case DataType::Type::kInt32: {
    774           DCHECK_EQ(2u, instruction->GetVectorLength());
    775           UseScratchRegisterScope temps(GetVIXLAssembler());
    776           vixl32::DRegister tmp = temps.AcquireD();
    777           __ Vsub(DataTypeValue::I32, tmp, left, right);
    778           __ Vabs(DataTypeValue::S32, tmp, tmp);
    779           __ Vadd(DataTypeValue::I32, acc, acc, tmp);
    780           break;
    781         }
    782         default:
    783           LOG(FATAL) << "Unsupported SIMD type";
    784           UNREACHABLE();
    785       }
    786       break;
    787     default:
    788       LOG(FATAL) << "Unsupported SIMD type";
    789       UNREACHABLE();
    790   }
    791 }
    792 
    793 // Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word
    794 // size equals to 4).
    795 static bool IsWordAligned(HVecMemoryOperation* instruction) {
    796   return instruction->GetAlignment().IsAlignedAt(4u);
    797 }
    798 
    799 // Helper to set up locations for vector memory operations.
    800 static void CreateVecMemLocations(ArenaAllocator* allocator,
    801                                   HVecMemoryOperation* instruction,
    802                                   bool is_load) {
    803   LocationSummary* locations = new (allocator) LocationSummary(instruction);
    804   switch (instruction->GetPackedType()) {
    805     case DataType::Type::kBool:
    806     case DataType::Type::kUint8:
    807     case DataType::Type::kInt8:
    808     case DataType::Type::kUint16:
    809     case DataType::Type::kInt16:
    810     case DataType::Type::kInt32:
    811       locations->SetInAt(0, Location::RequiresRegister());
    812       locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
    813       if (is_load) {
    814         locations->SetOut(Location::RequiresFpuRegister());
    815       } else {
    816         locations->SetInAt(2, Location::RequiresFpuRegister());
    817       }
    818       break;
    819     default:
    820       LOG(FATAL) << "Unsupported SIMD type";
    821       UNREACHABLE();
    822   }
    823 }
    824 
    825 // Helper to set up locations for vector memory operations. Returns the memory operand and,
    826 // if used, sets the output parameter scratch to a temporary register used in this operand,
    827 // so that the client can release it right after the memory operand use.
    828 MemOperand InstructionCodeGeneratorARMVIXL::VecAddress(
    829         HVecMemoryOperation* instruction,
    830         UseScratchRegisterScope* temps_scope,
    831         /*out*/ vixl32::Register* scratch) {
    832   LocationSummary* locations = instruction->GetLocations();
    833   vixl32::Register base = InputRegisterAt(instruction, 0);
    834 
    835   Location index = locations->InAt(1);
    836   size_t size = DataType::Size(instruction->GetPackedType());
    837   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
    838   size_t shift = ComponentSizeShiftWidth(size);
    839 
    840   // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
    841   DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
    842 
    843   if (index.IsConstant()) {
    844     offset += Int64ConstantFrom(index) << shift;
    845     return MemOperand(base, offset);
    846   } else {
    847     *scratch = temps_scope->Acquire();
    848     __ Add(*scratch, base, Operand(RegisterFrom(index), ShiftType::LSL, shift));
    849 
    850     return MemOperand(*scratch, offset);
    851   }
    852 }
    853 
    854 AlignedMemOperand InstructionCodeGeneratorARMVIXL::VecAddressUnaligned(
    855         HVecMemoryOperation* instruction,
    856         UseScratchRegisterScope* temps_scope,
    857         /*out*/ vixl32::Register* scratch) {
    858   LocationSummary* locations = instruction->GetLocations();
    859   vixl32::Register base = InputRegisterAt(instruction, 0);
    860 
    861   Location index = locations->InAt(1);
    862   size_t size = DataType::Size(instruction->GetPackedType());
    863   uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
    864   size_t shift = ComponentSizeShiftWidth(size);
    865 
    866   // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
    867   DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
    868 
    869   if (index.IsConstant()) {
    870     offset += Int64ConstantFrom(index) << shift;
    871     __ Add(*scratch, base, offset);
    872   } else {
    873     *scratch = temps_scope->Acquire();
    874     __ Add(*scratch, base, offset);
    875     __ Add(*scratch, *scratch, Operand(RegisterFrom(index), ShiftType::LSL, shift));
    876   }
    877   return AlignedMemOperand(*scratch, kNoAlignment);
    878 }
    879 
    880 void LocationsBuilderARMVIXL::VisitVecLoad(HVecLoad* instruction) {
    881   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /*is_load*/ true);
    882 }
    883 
    884 void InstructionCodeGeneratorARMVIXL::VisitVecLoad(HVecLoad* instruction) {
    885   vixl32::DRegister reg = OutputDRegister(instruction);
    886   UseScratchRegisterScope temps(GetVIXLAssembler());
    887   vixl32::Register scratch;
    888 
    889   DCHECK(instruction->GetPackedType() != DataType::Type::kUint16 || !instruction->IsStringCharAt());
    890 
    891   switch (instruction->GetPackedType()) {
    892     case DataType::Type::kBool:
    893     case DataType::Type::kUint8:
    894     case DataType::Type::kInt8:
    895       DCHECK_EQ(8u, instruction->GetVectorLength());
    896       if (IsWordAligned(instruction)) {
    897         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    898       } else {
    899         __ Vld1(Untyped8,
    900             NeonRegisterList(reg, kMultipleLanes),
    901             VecAddressUnaligned(instruction, &temps, &scratch));
    902       }
    903       break;
    904     case DataType::Type::kUint16:
    905     case DataType::Type::kInt16:
    906       DCHECK_EQ(4u, instruction->GetVectorLength());
    907       if (IsWordAligned(instruction)) {
    908         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    909       } else {
    910         __ Vld1(Untyped16,
    911             NeonRegisterList(reg, kMultipleLanes),
    912             VecAddressUnaligned(instruction, &temps, &scratch));
    913       }
    914       break;
    915     case DataType::Type::kInt32:
    916       DCHECK_EQ(2u, instruction->GetVectorLength());
    917       if (IsWordAligned(instruction)) {
    918         __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
    919       } else {
    920         __ Vld1(Untyped32,
    921             NeonRegisterList(reg, kMultipleLanes),
    922             VecAddressUnaligned(instruction, &temps, &scratch));
    923       }
    924       break;
    925     default:
    926       LOG(FATAL) << "Unsupported SIMD type";
    927       UNREACHABLE();
    928   }
    929 }
    930 
    931 void LocationsBuilderARMVIXL::VisitVecStore(HVecStore* instruction) {
    932   CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /*is_load*/ false);
    933 }
    934 
    935 void InstructionCodeGeneratorARMVIXL::VisitVecStore(HVecStore* instruction) {
    936   vixl32::DRegister reg = InputDRegisterAt(instruction, 2);
    937   UseScratchRegisterScope temps(GetVIXLAssembler());
    938   vixl32::Register scratch;
    939   switch (instruction->GetPackedType()) {
    940     case DataType::Type::kBool:
    941     case DataType::Type::kUint8:
    942     case DataType::Type::kInt8:
    943       DCHECK_EQ(8u, instruction->GetVectorLength());
    944       if (IsWordAligned(instruction)) {
    945         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
    946       } else {
    947         __ Vst1(Untyped8,
    948                 NeonRegisterList(reg, kMultipleLanes),
    949                 VecAddressUnaligned(instruction, &temps, &scratch));
    950       }
    951       break;
    952     case DataType::Type::kUint16:
    953     case DataType::Type::kInt16:
    954       DCHECK_EQ(4u, instruction->GetVectorLength());
    955       if (IsWordAligned(instruction)) {
    956         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
    957       } else {
    958         __ Vst1(Untyped16,
    959                 NeonRegisterList(reg, kMultipleLanes),
    960                 VecAddressUnaligned(instruction, &temps, &scratch));
    961       }
    962       break;
    963     case DataType::Type::kInt32:
    964       DCHECK_EQ(2u, instruction->GetVectorLength());
    965       if (IsWordAligned(instruction)) {
    966         __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
    967       } else {
    968         __ Vst1(Untyped32,
    969                 NeonRegisterList(reg, kMultipleLanes),
    970                 VecAddressUnaligned(instruction, &temps, &scratch));
    971       }
    972       break;
    973     default:
    974       LOG(FATAL) << "Unsupported SIMD type";
    975       UNREACHABLE();
    976   }
    977 }
    978 
    979 #undef __
    980 
    981 }  // namespace arm
    982 }  // namespace art
    983