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 #ifndef ART_COMPILER_OPTIMIZING_NODES_VECTOR_H_
     18 #define ART_COMPILER_OPTIMIZING_NODES_VECTOR_H_
     19 
     20 // This #include should never be used by compilation, because this header file (nodes_vector.h)
     21 // is included in the header file nodes.h itself. However it gives editing tools better context.
     22 #include "nodes.h"
     23 
     24 namespace art {
     25 
     26 // Memory alignment, represented as an offset relative to a base, where 0 <= offset < base,
     27 // and base is a power of two. For example, the value Alignment(16, 0) means memory is
     28 // perfectly aligned at a 16-byte boundary, whereas the value Alignment(16, 4) means
     29 // memory is always exactly 4 bytes above such a boundary.
     30 class Alignment {
     31  public:
     32   Alignment(size_t base, size_t offset) : base_(base), offset_(offset) {
     33     DCHECK_LT(offset, base);
     34     DCHECK(IsPowerOfTwo(base));
     35   }
     36 
     37   // Returns true if memory is "at least" aligned at the given boundary.
     38   // Assumes requested base is power of two.
     39   bool IsAlignedAt(size_t base) const {
     40     DCHECK_NE(0u, base);
     41     DCHECK(IsPowerOfTwo(base));
     42     return ((offset_ | base_) & (base - 1u)) == 0;
     43   }
     44 
     45   std::string ToString() const {
     46     return "ALIGN(" + std::to_string(base_) + "," + std::to_string(offset_) + ")";
     47   }
     48 
     49  private:
     50   size_t base_;
     51   size_t offset_;
     52 };
     53 
     54 //
     55 // Definitions of abstract vector operations in HIR.
     56 //
     57 
     58 // Abstraction of a vector operation, i.e., an operation that performs
     59 // GetVectorLength() x GetPackedType() operations simultaneously.
     60 class HVecOperation : public HVariableInputSizeInstruction {
     61  public:
     62   HVecOperation(ArenaAllocator* arena,
     63                 Primitive::Type packed_type,
     64                 SideEffects side_effects,
     65                 size_t number_of_inputs,
     66                 size_t vector_length,
     67                 uint32_t dex_pc)
     68       : HVariableInputSizeInstruction(side_effects,
     69                                       dex_pc,
     70                                       arena,
     71                                       number_of_inputs,
     72                                       kArenaAllocVectorNode),
     73         vector_length_(vector_length) {
     74     SetPackedField<TypeField>(packed_type);
     75     DCHECK_LT(1u, vector_length);
     76   }
     77 
     78   // Returns the number of elements packed in a vector.
     79   size_t GetVectorLength() const {
     80     return vector_length_;
     81   }
     82 
     83   // Returns the number of bytes in a full vector.
     84   size_t GetVectorNumberOfBytes() const {
     85     return vector_length_ * Primitive::ComponentSize(GetPackedType());
     86   }
     87 
     88   // Returns the type of the vector operation: a SIMD operation looks like a FPU location.
     89   // TODO: we could introduce SIMD types in HIR.
     90   Primitive::Type GetType() const OVERRIDE {
     91     return Primitive::kPrimDouble;
     92   }
     93 
     94   // Returns the true component type packed in a vector.
     95   Primitive::Type GetPackedType() const {
     96     return GetPackedField<TypeField>();
     97   }
     98 
     99   DECLARE_ABSTRACT_INSTRUCTION(VecOperation);
    100 
    101  protected:
    102   // Additional packed bits.
    103   static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
    104   static constexpr size_t kFieldTypeSize =
    105       MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
    106   static constexpr size_t kNumberOfVectorOpPackedBits = kFieldType + kFieldTypeSize;
    107   static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
    108   using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
    109 
    110  private:
    111   const size_t vector_length_;
    112 
    113   DISALLOW_COPY_AND_ASSIGN(HVecOperation);
    114 };
    115 
    116 // Abstraction of a unary vector operation.
    117 class HVecUnaryOperation : public HVecOperation {
    118  public:
    119   HVecUnaryOperation(ArenaAllocator* arena,
    120                      HInstruction* input,
    121                      Primitive::Type packed_type,
    122                      size_t vector_length,
    123                      uint32_t dex_pc)
    124       : HVecOperation(arena,
    125                       packed_type,
    126                       SideEffects::None(),
    127                       /* number_of_inputs */ 1,
    128                       vector_length,
    129                       dex_pc) {
    130     SetRawInputAt(0, input);
    131   }
    132 
    133   HInstruction* GetInput() const { return InputAt(0); }
    134 
    135   DECLARE_ABSTRACT_INSTRUCTION(VecUnaryOperation);
    136 
    137  private:
    138   DISALLOW_COPY_AND_ASSIGN(HVecUnaryOperation);
    139 };
    140 
    141 // Abstraction of a binary vector operation.
    142 class HVecBinaryOperation : public HVecOperation {
    143  public:
    144   HVecBinaryOperation(ArenaAllocator* arena,
    145                       HInstruction* left,
    146                       HInstruction* right,
    147                       Primitive::Type packed_type,
    148                       size_t vector_length,
    149                       uint32_t dex_pc)
    150       : HVecOperation(arena,
    151                       packed_type,
    152                       SideEffects::None(),
    153                       /* number_of_inputs */ 2,
    154                       vector_length,
    155                       dex_pc) {
    156     SetRawInputAt(0, left);
    157     SetRawInputAt(1, right);
    158   }
    159 
    160   HInstruction* GetLeft() const { return InputAt(0); }
    161   HInstruction* GetRight() const { return InputAt(1); }
    162 
    163   DECLARE_ABSTRACT_INSTRUCTION(VecBinaryOperation);
    164 
    165  private:
    166   DISALLOW_COPY_AND_ASSIGN(HVecBinaryOperation);
    167 };
    168 
    169 // Abstraction of a vector operation that references memory, with an alignment.
    170 // The Android runtime guarantees at least "component size" alignment for array
    171 // elements and, thus, vectors.
    172 class HVecMemoryOperation : public HVecOperation {
    173  public:
    174   HVecMemoryOperation(ArenaAllocator* arena,
    175                       Primitive::Type packed_type,
    176                       SideEffects side_effects,
    177                       size_t number_of_inputs,
    178                       size_t vector_length,
    179                       uint32_t dex_pc)
    180       : HVecOperation(arena, packed_type, side_effects, number_of_inputs, vector_length, dex_pc),
    181         alignment_(Primitive::ComponentSize(packed_type), 0) { }
    182 
    183   void SetAlignment(Alignment alignment) { alignment_ = alignment; }
    184 
    185   Alignment GetAlignment() const { return alignment_; }
    186 
    187   DECLARE_ABSTRACT_INSTRUCTION(VecMemoryOperation);
    188 
    189  private:
    190   Alignment alignment_;
    191 
    192   DISALLOW_COPY_AND_ASSIGN(HVecMemoryOperation);
    193 };
    194 
    195 // Packed type consistency checker (same vector length integral types may mix freely).
    196 inline static bool HasConsistentPackedTypes(HInstruction* input, Primitive::Type type) {
    197   DCHECK(input->IsVecOperation());
    198   Primitive::Type input_type = input->AsVecOperation()->GetPackedType();
    199   switch (input_type) {
    200     case Primitive::kPrimBoolean:
    201     case Primitive::kPrimByte:
    202       return type == Primitive::kPrimBoolean ||
    203              type == Primitive::kPrimByte;
    204     case Primitive::kPrimChar:
    205     case Primitive::kPrimShort:
    206       return type == Primitive::kPrimChar ||
    207              type == Primitive::kPrimShort;
    208     default:
    209       return type == input_type;
    210   }
    211 }
    212 
    213 //
    214 // Definitions of concrete unary vector operations in HIR.
    215 //
    216 
    217 // Replicates the given scalar into a vector,
    218 // viz. replicate(x) = [ x, .. , x ].
    219 class HVecReplicateScalar FINAL : public HVecUnaryOperation {
    220  public:
    221   HVecReplicateScalar(ArenaAllocator* arena,
    222                       HInstruction* scalar,
    223                       Primitive::Type packed_type,
    224                       size_t vector_length,
    225                       uint32_t dex_pc = kNoDexPc)
    226       : HVecUnaryOperation(arena, scalar, packed_type, vector_length, dex_pc) {
    227     DCHECK(!scalar->IsVecOperation());
    228   }
    229   DECLARE_INSTRUCTION(VecReplicateScalar);
    230  private:
    231   DISALLOW_COPY_AND_ASSIGN(HVecReplicateScalar);
    232 };
    233 
    234 // Sum-reduces the given vector into a shorter vector (m < n) or scalar (m = 1),
    235 // viz. sum-reduce[ x1, .. , xn ] = [ y1, .., ym ], where yi = sum_j x_j.
    236 class HVecSumReduce FINAL : public HVecUnaryOperation {
    237   HVecSumReduce(ArenaAllocator* arena,
    238                 HInstruction* input,
    239                 Primitive::Type packed_type,
    240                 size_t vector_length,
    241                 uint32_t dex_pc = kNoDexPc)
    242       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
    243     DCHECK(HasConsistentPackedTypes(input, packed_type));
    244   }
    245 
    246   // TODO: probably integral promotion
    247   Primitive::Type GetType() const OVERRIDE { return GetPackedType(); }
    248 
    249   DECLARE_INSTRUCTION(VecSumReduce);
    250  private:
    251   DISALLOW_COPY_AND_ASSIGN(HVecSumReduce);
    252 };
    253 
    254 // Converts every component in the vector,
    255 // viz. cnv[ x1, .. , xn ]  = [ cnv(x1), .. , cnv(xn) ].
    256 class HVecCnv FINAL : public HVecUnaryOperation {
    257  public:
    258   HVecCnv(ArenaAllocator* arena,
    259           HInstruction* input,
    260           Primitive::Type packed_type,
    261           size_t vector_length,
    262           uint32_t dex_pc = kNoDexPc)
    263       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
    264     DCHECK(input->IsVecOperation());
    265     DCHECK_NE(GetInputType(), GetResultType());  // actual convert
    266   }
    267 
    268   Primitive::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); }
    269   Primitive::Type GetResultType() const { return GetPackedType(); }
    270 
    271   DECLARE_INSTRUCTION(VecCnv);
    272 
    273  private:
    274   DISALLOW_COPY_AND_ASSIGN(HVecCnv);
    275 };
    276 
    277 // Negates every component in the vector,
    278 // viz. neg[ x1, .. , xn ]  = [ -x1, .. , -xn ].
    279 class HVecNeg FINAL : public HVecUnaryOperation {
    280  public:
    281   HVecNeg(ArenaAllocator* arena,
    282           HInstruction* input,
    283           Primitive::Type packed_type,
    284           size_t vector_length,
    285           uint32_t dex_pc = kNoDexPc)
    286       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
    287     DCHECK(HasConsistentPackedTypes(input, packed_type));
    288   }
    289   DECLARE_INSTRUCTION(VecNeg);
    290  private:
    291   DISALLOW_COPY_AND_ASSIGN(HVecNeg);
    292 };
    293 
    294 // Takes absolute value of every component in the vector,
    295 // viz. abs[ x1, .. , xn ]  = [ |x1|, .. , |xn| ].
    296 class HVecAbs FINAL : public HVecUnaryOperation {
    297  public:
    298   HVecAbs(ArenaAllocator* arena,
    299           HInstruction* input,
    300           Primitive::Type packed_type,
    301           size_t vector_length,
    302           uint32_t dex_pc = kNoDexPc)
    303       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
    304     DCHECK(HasConsistentPackedTypes(input, packed_type));
    305   }
    306   DECLARE_INSTRUCTION(VecAbs);
    307  private:
    308   DISALLOW_COPY_AND_ASSIGN(HVecAbs);
    309 };
    310 
    311 // Bitwise- or boolean-nots every component in the vector,
    312 // viz. not[ x1, .. , xn ]  = [ ~x1, .. , ~xn ], or
    313 //      not[ x1, .. , xn ]  = [ !x1, .. , !xn ] for boolean.
    314 class HVecNot FINAL : public HVecUnaryOperation {
    315  public:
    316   HVecNot(ArenaAllocator* arena,
    317           HInstruction* input,
    318           Primitive::Type packed_type,
    319           size_t vector_length,
    320           uint32_t dex_pc = kNoDexPc)
    321       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
    322     DCHECK(input->IsVecOperation());
    323   }
    324   DECLARE_INSTRUCTION(VecNot);
    325  private:
    326   DISALLOW_COPY_AND_ASSIGN(HVecNot);
    327 };
    328 
    329 //
    330 // Definitions of concrete binary vector operations in HIR.
    331 //
    332 
    333 // Adds every component in the two vectors,
    334 // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 + y1, .. , xn + yn ].
    335 class HVecAdd FINAL : public HVecBinaryOperation {
    336  public:
    337   HVecAdd(ArenaAllocator* arena,
    338           HInstruction* left,
    339           HInstruction* right,
    340           Primitive::Type packed_type,
    341           size_t vector_length,
    342           uint32_t dex_pc = kNoDexPc)
    343       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    344     DCHECK(HasConsistentPackedTypes(left, packed_type));
    345     DCHECK(HasConsistentPackedTypes(right, packed_type));
    346   }
    347   DECLARE_INSTRUCTION(VecAdd);
    348  private:
    349   DISALLOW_COPY_AND_ASSIGN(HVecAdd);
    350 };
    351 
    352 // Performs halving add on every component in the two vectors, viz.
    353 // rounded [ x1, .. , xn ] hradd [ y1, .. , yn ] = [ (x1 + y1 + 1) >> 1, .. , (xn + yn + 1) >> 1 ]
    354 // or      [ x1, .. , xn ] hadd  [ y1, .. , yn ] = [ (x1 + y1)     >> 1, .. , (xn + yn )    >> 1 ]
    355 // for signed operands x, y (sign extension) or unsigned operands x, y (zero extension).
    356 class HVecHalvingAdd FINAL : public HVecBinaryOperation {
    357  public:
    358   HVecHalvingAdd(ArenaAllocator* arena,
    359                  HInstruction* left,
    360                  HInstruction* right,
    361                  Primitive::Type packed_type,
    362                  size_t vector_length,
    363                  bool is_unsigned,
    364                  bool is_rounded,
    365                  uint32_t dex_pc = kNoDexPc)
    366       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    367     DCHECK(HasConsistentPackedTypes(left, packed_type));
    368     DCHECK(HasConsistentPackedTypes(right, packed_type));
    369     SetPackedFlag<kFieldHAddIsUnsigned>(is_unsigned);
    370     SetPackedFlag<kFieldHAddIsRounded>(is_rounded);
    371   }
    372 
    373   bool IsUnsigned() const { return GetPackedFlag<kFieldHAddIsUnsigned>(); }
    374   bool IsRounded() const { return GetPackedFlag<kFieldHAddIsRounded>(); }
    375 
    376   DECLARE_INSTRUCTION(VecHalvingAdd);
    377 
    378  private:
    379   // Additional packed bits.
    380   static constexpr size_t kFieldHAddIsUnsigned = HVecOperation::kNumberOfVectorOpPackedBits;
    381   static constexpr size_t kFieldHAddIsRounded = kFieldHAddIsUnsigned + 1;
    382   static constexpr size_t kNumberOfHAddPackedBits = kFieldHAddIsRounded + 1;
    383   static_assert(kNumberOfHAddPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
    384 
    385   DISALLOW_COPY_AND_ASSIGN(HVecHalvingAdd);
    386 };
    387 
    388 // Subtracts every component in the two vectors,
    389 // viz. [ x1, .. , xn ] - [ y1, .. , yn ] = [ x1 - y1, .. , xn - yn ].
    390 class HVecSub FINAL : public HVecBinaryOperation {
    391  public:
    392   HVecSub(ArenaAllocator* arena,
    393           HInstruction* left,
    394           HInstruction* right,
    395           Primitive::Type packed_type,
    396           size_t vector_length,
    397           uint32_t dex_pc = kNoDexPc)
    398       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    399     DCHECK(HasConsistentPackedTypes(left, packed_type));
    400     DCHECK(HasConsistentPackedTypes(right, packed_type));
    401   }
    402   DECLARE_INSTRUCTION(VecSub);
    403  private:
    404   DISALLOW_COPY_AND_ASSIGN(HVecSub);
    405 };
    406 
    407 // Multiplies every component in the two vectors,
    408 // viz. [ x1, .. , xn ] * [ y1, .. , yn ] = [ x1 * y1, .. , xn * yn ].
    409 class HVecMul FINAL : public HVecBinaryOperation {
    410  public:
    411   HVecMul(ArenaAllocator* arena,
    412           HInstruction* left,
    413           HInstruction* right,
    414           Primitive::Type packed_type,
    415           size_t vector_length,
    416           uint32_t dex_pc = kNoDexPc)
    417       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    418     DCHECK(HasConsistentPackedTypes(left, packed_type));
    419     DCHECK(HasConsistentPackedTypes(right, packed_type));
    420   }
    421   DECLARE_INSTRUCTION(VecMul);
    422  private:
    423   DISALLOW_COPY_AND_ASSIGN(HVecMul);
    424 };
    425 
    426 // Divides every component in the two vectors,
    427 // viz. [ x1, .. , xn ] / [ y1, .. , yn ] = [ x1 / y1, .. , xn / yn ].
    428 class HVecDiv FINAL : public HVecBinaryOperation {
    429  public:
    430   HVecDiv(ArenaAllocator* arena,
    431           HInstruction* left,
    432           HInstruction* right,
    433           Primitive::Type packed_type,
    434           size_t vector_length,
    435           uint32_t dex_pc = kNoDexPc)
    436       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    437     DCHECK(HasConsistentPackedTypes(left, packed_type));
    438     DCHECK(HasConsistentPackedTypes(right, packed_type));
    439   }
    440   DECLARE_INSTRUCTION(VecDiv);
    441  private:
    442   DISALLOW_COPY_AND_ASSIGN(HVecDiv);
    443 };
    444 
    445 // Takes minimum of every component in the two vectors,
    446 // viz. MIN( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ min(x1, y1), .. , min(xn, yn) ].
    447 class HVecMin FINAL : public HVecBinaryOperation {
    448  public:
    449   HVecMin(ArenaAllocator* arena,
    450           HInstruction* left,
    451           HInstruction* right,
    452           Primitive::Type packed_type,
    453           size_t vector_length,
    454           uint32_t dex_pc = kNoDexPc)
    455       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    456     DCHECK(HasConsistentPackedTypes(left, packed_type));
    457     DCHECK(HasConsistentPackedTypes(right, packed_type));
    458   }
    459   DECLARE_INSTRUCTION(VecMin);
    460  private:
    461   DISALLOW_COPY_AND_ASSIGN(HVecMin);
    462 };
    463 
    464 // Takes maximum of every component in the two vectors,
    465 // viz. MAX( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ max(x1, y1), .. , max(xn, yn) ].
    466 class HVecMax FINAL : public HVecBinaryOperation {
    467  public:
    468   HVecMax(ArenaAllocator* arena,
    469           HInstruction* left,
    470           HInstruction* right,
    471           Primitive::Type packed_type,
    472           size_t vector_length,
    473           uint32_t dex_pc = kNoDexPc)
    474       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    475     DCHECK(HasConsistentPackedTypes(left, packed_type));
    476     DCHECK(HasConsistentPackedTypes(right, packed_type));
    477   }
    478   DECLARE_INSTRUCTION(VecMax);
    479  private:
    480   DISALLOW_COPY_AND_ASSIGN(HVecMax);
    481 };
    482 
    483 // Bitwise-ands every component in the two vectors,
    484 // viz. [ x1, .. , xn ] & [ y1, .. , yn ] = [ x1 & y1, .. , xn & yn ].
    485 class HVecAnd FINAL : public HVecBinaryOperation {
    486  public:
    487   HVecAnd(ArenaAllocator* arena,
    488           HInstruction* left,
    489           HInstruction* right,
    490           Primitive::Type packed_type,
    491           size_t vector_length,
    492           uint32_t dex_pc = kNoDexPc)
    493       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    494     DCHECK(left->IsVecOperation() && right->IsVecOperation());
    495   }
    496   DECLARE_INSTRUCTION(VecAnd);
    497  private:
    498   DISALLOW_COPY_AND_ASSIGN(HVecAnd);
    499 };
    500 
    501 // Bitwise-and-nots every component in the two vectors,
    502 // viz. [ x1, .. , xn ] and-not [ y1, .. , yn ] = [ ~x1 & y1, .. , ~xn & yn ].
    503 class HVecAndNot FINAL : public HVecBinaryOperation {
    504  public:
    505   HVecAndNot(ArenaAllocator* arena,
    506              HInstruction* left,
    507              HInstruction* right,
    508              Primitive::Type packed_type,
    509              size_t vector_length,
    510              uint32_t dex_pc = kNoDexPc)
    511          : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    512     DCHECK(left->IsVecOperation() && right->IsVecOperation());
    513   }
    514   DECLARE_INSTRUCTION(VecAndNot);
    515  private:
    516   DISALLOW_COPY_AND_ASSIGN(HVecAndNot);
    517 };
    518 
    519 // Bitwise-ors every component in the two vectors,
    520 // viz. [ x1, .. , xn ] | [ y1, .. , yn ] = [ x1 | y1, .. , xn | yn ].
    521 class HVecOr FINAL : public HVecBinaryOperation {
    522  public:
    523   HVecOr(ArenaAllocator* arena,
    524          HInstruction* left,
    525          HInstruction* right,
    526          Primitive::Type packed_type,
    527          size_t vector_length,
    528          uint32_t dex_pc = kNoDexPc)
    529       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    530     DCHECK(left->IsVecOperation() && right->IsVecOperation());
    531   }
    532   DECLARE_INSTRUCTION(VecOr);
    533  private:
    534   DISALLOW_COPY_AND_ASSIGN(HVecOr);
    535 };
    536 
    537 // Bitwise-xors every component in the two vectors,
    538 // viz. [ x1, .. , xn ] ^ [ y1, .. , yn ] = [ x1 ^ y1, .. , xn ^ yn ].
    539 class HVecXor FINAL : public HVecBinaryOperation {
    540  public:
    541   HVecXor(ArenaAllocator* arena,
    542           HInstruction* left,
    543           HInstruction* right,
    544           Primitive::Type packed_type,
    545           size_t vector_length,
    546           uint32_t dex_pc = kNoDexPc)
    547       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    548     DCHECK(left->IsVecOperation() && right->IsVecOperation());
    549   }
    550   DECLARE_INSTRUCTION(VecXor);
    551  private:
    552   DISALLOW_COPY_AND_ASSIGN(HVecXor);
    553 };
    554 
    555 // Logically shifts every component in the vector left by the given distance,
    556 // viz. [ x1, .. , xn ] << d = [ x1 << d, .. , xn << d ].
    557 class HVecShl FINAL : public HVecBinaryOperation {
    558  public:
    559   HVecShl(ArenaAllocator* arena,
    560           HInstruction* left,
    561           HInstruction* right,
    562           Primitive::Type packed_type,
    563           size_t vector_length,
    564           uint32_t dex_pc = kNoDexPc)
    565       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    566     DCHECK(HasConsistentPackedTypes(left, packed_type));
    567   }
    568   DECLARE_INSTRUCTION(VecShl);
    569  private:
    570   DISALLOW_COPY_AND_ASSIGN(HVecShl);
    571 };
    572 
    573 // Arithmetically shifts every component in the vector right by the given distance,
    574 // viz. [ x1, .. , xn ] >> d = [ x1 >> d, .. , xn >> d ].
    575 class HVecShr FINAL : public HVecBinaryOperation {
    576  public:
    577   HVecShr(ArenaAllocator* arena,
    578           HInstruction* left,
    579           HInstruction* right,
    580           Primitive::Type packed_type,
    581           size_t vector_length,
    582           uint32_t dex_pc = kNoDexPc)
    583       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    584     DCHECK(HasConsistentPackedTypes(left, packed_type));
    585   }
    586   DECLARE_INSTRUCTION(VecShr);
    587  private:
    588   DISALLOW_COPY_AND_ASSIGN(HVecShr);
    589 };
    590 
    591 // Logically shifts every component in the vector right by the given distance,
    592 // viz. [ x1, .. , xn ] >>> d = [ x1 >>> d, .. , xn >>> d ].
    593 class HVecUShr FINAL : public HVecBinaryOperation {
    594  public:
    595   HVecUShr(ArenaAllocator* arena,
    596            HInstruction* left,
    597            HInstruction* right,
    598            Primitive::Type packed_type,
    599            size_t vector_length,
    600            uint32_t dex_pc = kNoDexPc)
    601       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
    602     DCHECK(HasConsistentPackedTypes(left, packed_type));
    603   }
    604   DECLARE_INSTRUCTION(VecUShr);
    605  private:
    606   DISALLOW_COPY_AND_ASSIGN(HVecUShr);
    607 };
    608 
    609 //
    610 // Definitions of concrete miscellaneous vector operations in HIR.
    611 //
    612 
    613 // Assigns the given scalar elements to a vector,
    614 // viz. set( array(x1, .., xn) ) = [ x1, .. , xn ].
    615 class HVecSetScalars FINAL : public HVecOperation {
    616   HVecSetScalars(ArenaAllocator* arena,
    617                  HInstruction** scalars,  // array
    618                  Primitive::Type packed_type,
    619                  size_t vector_length,
    620                  uint32_t dex_pc = kNoDexPc)
    621       : HVecOperation(arena,
    622                       packed_type,
    623                       SideEffects::None(),
    624                       /* number_of_inputs */ vector_length,
    625                       vector_length,
    626                       dex_pc) {
    627     for (size_t i = 0; i < vector_length; i++) {
    628       DCHECK(!scalars[i]->IsVecOperation());
    629       SetRawInputAt(0, scalars[i]);
    630     }
    631   }
    632   DECLARE_INSTRUCTION(VecSetScalars);
    633  private:
    634   DISALLOW_COPY_AND_ASSIGN(HVecSetScalars);
    635 };
    636 
    637 // Multiplies every component in the two vectors, adds the result vector to the accumulator vector.
    638 // viz. [ acc1, .., accn ] + [ x1, .. , xn ] * [ y1, .. , yn ] =
    639 //     [ acc1 + x1 * y1, .. , accn + xn * yn ].
    640 class HVecMultiplyAccumulate FINAL : public HVecOperation {
    641  public:
    642   HVecMultiplyAccumulate(ArenaAllocator* arena,
    643                          InstructionKind op,
    644                          HInstruction* accumulator,
    645                          HInstruction* mul_left,
    646                          HInstruction* mul_right,
    647                          Primitive::Type packed_type,
    648                          size_t vector_length,
    649                          uint32_t dex_pc = kNoDexPc)
    650       : HVecOperation(arena,
    651                       packed_type,
    652                       SideEffects::None(),
    653                       /* number_of_inputs */ 3,
    654                       vector_length,
    655                       dex_pc),
    656         op_kind_(op) {
    657     DCHECK(op == InstructionKind::kAdd || op == InstructionKind::kSub);
    658     DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
    659     DCHECK(HasConsistentPackedTypes(mul_left, packed_type));
    660     DCHECK(HasConsistentPackedTypes(mul_right, packed_type));
    661     SetRawInputAt(kInputAccumulatorIndex, accumulator);
    662     SetRawInputAt(kInputMulLeftIndex, mul_left);
    663     SetRawInputAt(kInputMulRightIndex, mul_right);
    664   }
    665 
    666   static constexpr int kInputAccumulatorIndex = 0;
    667   static constexpr int kInputMulLeftIndex = 1;
    668   static constexpr int kInputMulRightIndex = 2;
    669 
    670   bool CanBeMoved() const OVERRIDE { return true; }
    671 
    672   bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
    673     return op_kind_ == other->AsVecMultiplyAccumulate()->op_kind_;
    674   }
    675 
    676   InstructionKind GetOpKind() const { return op_kind_; }
    677 
    678   DECLARE_INSTRUCTION(VecMultiplyAccumulate);
    679 
    680  private:
    681   // Indicates if this is a MADD or MSUB.
    682   const InstructionKind op_kind_;
    683 
    684   DISALLOW_COPY_AND_ASSIGN(HVecMultiplyAccumulate);
    685 };
    686 
    687 // Loads a vector from memory, viz. load(mem, 1)
    688 // yield the vector [ mem(1), .. , mem(n) ].
    689 class HVecLoad FINAL : public HVecMemoryOperation {
    690  public:
    691   HVecLoad(ArenaAllocator* arena,
    692            HInstruction* base,
    693            HInstruction* index,
    694            Primitive::Type packed_type,
    695            size_t vector_length,
    696            bool is_string_char_at,
    697            uint32_t dex_pc = kNoDexPc)
    698       : HVecMemoryOperation(arena,
    699                             packed_type,
    700                             SideEffects::ArrayReadOfType(packed_type),
    701                             /* number_of_inputs */ 2,
    702                             vector_length,
    703                             dex_pc) {
    704     SetRawInputAt(0, base);
    705     SetRawInputAt(1, index);
    706     SetPackedFlag<kFieldIsStringCharAt>(is_string_char_at);
    707   }
    708   DECLARE_INSTRUCTION(VecLoad);
    709 
    710   bool IsStringCharAt() const { return GetPackedFlag<kFieldIsStringCharAt>(); }
    711 
    712  private:
    713   // Additional packed bits.
    714   static constexpr size_t kFieldIsStringCharAt = HVecOperation::kNumberOfVectorOpPackedBits;
    715   static constexpr size_t kNumberOfVecLoadPackedBits = kFieldIsStringCharAt + 1;
    716   static_assert(kNumberOfVecLoadPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
    717 
    718   DISALLOW_COPY_AND_ASSIGN(HVecLoad);
    719 };
    720 
    721 // Stores a vector to memory, viz. store(m, 1, [x1, .. , xn] )
    722 // sets mem(1) = x1, .. , mem(n) = xn.
    723 class HVecStore FINAL : public HVecMemoryOperation {
    724  public:
    725   HVecStore(ArenaAllocator* arena,
    726             HInstruction* base,
    727             HInstruction* index,
    728             HInstruction* value,
    729             Primitive::Type packed_type,
    730             size_t vector_length,
    731             uint32_t dex_pc = kNoDexPc)
    732       : HVecMemoryOperation(arena,
    733                             packed_type,
    734                             SideEffects::ArrayWriteOfType(packed_type),
    735                             /* number_of_inputs */ 3,
    736                             vector_length,
    737                             dex_pc) {
    738     DCHECK(HasConsistentPackedTypes(value, packed_type));
    739     SetRawInputAt(0, base);
    740     SetRawInputAt(1, index);
    741     SetRawInputAt(2, value);
    742   }
    743   DECLARE_INSTRUCTION(VecStore);
    744  private:
    745   DISALLOW_COPY_AND_ASSIGN(HVecStore);
    746 };
    747 
    748 }  // namespace art
    749 
    750 #endif  // ART_COMPILER_OPTIMIZING_NODES_VECTOR_H_
    751