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:
Alignment(size_t base,size_t offset)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.
IsAlignedAt(size_t base)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 
Base()45   size_t Base() const { return base_; }
46 
Offset()47   size_t Offset() const { return offset_; }
48 
ToString()49   std::string ToString() const {
50     return "ALIGN(" + std::to_string(base_) + "," + std::to_string(offset_) + ")";
51   }
52 
53   bool operator==(const Alignment& other) const {
54     return base_ == other.base_ && offset_ == other.offset_;
55   }
56 
57  private:
58   size_t base_;
59   size_t offset_;
60 };
61 
62 //
63 // Definitions of abstract vector operations in HIR.
64 //
65 
66 // Abstraction of a vector operation, i.e., an operation that performs
67 // GetVectorLength() x GetPackedType() operations simultaneously.
68 class HVecOperation : public HVariableInputSizeInstruction {
69  public:
70   // A SIMD operation looks like a FPU location.
71   // TODO: we could introduce SIMD types in HIR.
72   static constexpr DataType::Type kSIMDType = DataType::Type::kFloat64;
73 
HVecOperation(InstructionKind kind,ArenaAllocator * allocator,DataType::Type packed_type,SideEffects side_effects,size_t number_of_inputs,size_t vector_length,uint32_t dex_pc)74   HVecOperation(InstructionKind kind,
75                 ArenaAllocator* allocator,
76                 DataType::Type packed_type,
77                 SideEffects side_effects,
78                 size_t number_of_inputs,
79                 size_t vector_length,
80                 uint32_t dex_pc)
81       : HVariableInputSizeInstruction(kind,
82                                       kSIMDType,
83                                       side_effects,
84                                       dex_pc,
85                                       allocator,
86                                       number_of_inputs,
87                                       kArenaAllocVectorNode),
88         vector_length_(vector_length) {
89     SetPackedField<PackedTypeField>(packed_type);
90     // By default vector operations are not predicated.
91     SetPackedField<PredicationKindField>(PredicationKind::kNotPredicated);
92     DCHECK_LT(1u, vector_length);
93   }
94 
95   // Predicated instructions execute a corresponding operation only on vector elements which are
96   // active (governing predicate is true for that element); the following modes determine what
97   // is happening with inactive elements.
98   //
99   // See HVecPredSetOperation.
100   enum class PredicationKind {
101     kNotPredicated,        // Instruction doesn't take any predicate as an input.
102     kZeroingForm,          // Inactive elements are reset to zero.
103     kMergingForm,          // Inactive elements keep their value.
104     kLast = kMergingForm,
105   };
106 
GetPredicationKind()107   PredicationKind GetPredicationKind() const { return GetPackedField<PredicationKindField>(); }
108 
109   // Returns whether the vector operation must be predicated in predicated SIMD mode
110   // (see CodeGenerator::SupportsPredicatedSIMD). The method reflects semantics of
111   // the instruction class rather than the state of a particular instruction instance.
112   //
113   // This property is introduced for robustness purpose - to maintain and check the invariant:
114   // all instructions of the same vector operation class must be either all predicated or all
115   // not predicated (depending on the predicated SIMD support) in a correct graph.
MustBePredicatedInPredicatedSIMDMode()116   virtual bool MustBePredicatedInPredicatedSIMDMode() {
117     return true;
118   }
119 
IsPredicated()120   bool IsPredicated() const {
121     return GetPredicationKind() != PredicationKind::kNotPredicated;
122   }
123 
124   // See HVecPredSetOperation.
SetGoverningPredicate(HInstruction * input,PredicationKind pred_kind)125   void SetGoverningPredicate(HInstruction* input, PredicationKind pred_kind) {
126     DCHECK(!IsPredicated());
127     DCHECK(input->IsVecPredSetOperation());
128     AddInput(input);
129     SetPackedField<PredicationKindField>(pred_kind);
130     DCHECK(IsPredicated());
131   }
132 
SetMergingGoverningPredicate(HInstruction * input)133   void SetMergingGoverningPredicate(HInstruction* input) {
134     SetGoverningPredicate(input, PredicationKind::kMergingForm);
135   }
SetZeroingGoverningPredicate(HInstruction * input)136   void SetZeroingGoverningPredicate(HInstruction* input) {
137     SetGoverningPredicate(input, PredicationKind::kZeroingForm);
138   }
139 
140   // See HVecPredSetOperation.
GetGoverningPredicate()141   HVecPredSetOperation* GetGoverningPredicate() const {
142     DCHECK(IsPredicated());
143     HInstruction* pred_input = InputAt(InputCount() - 1);
144     DCHECK(pred_input->IsVecPredSetOperation());
145     return pred_input->AsVecPredSetOperation();
146   }
147 
148   // Returns the number of elements packed in a vector.
GetVectorLength()149   size_t GetVectorLength() const {
150     return vector_length_;
151   }
152 
153   // Returns the number of bytes in a full vector.
GetVectorNumberOfBytes()154   size_t GetVectorNumberOfBytes() const {
155     return vector_length_ * DataType::Size(GetPackedType());
156   }
157 
158   // Returns the true component type packed in a vector.
GetPackedType()159   DataType::Type GetPackedType() const {
160     return GetPackedField<PackedTypeField>();
161   }
162 
163   // Assumes vector nodes cannot be moved by default. Each concrete implementation
164   // that can be moved should override this method and return true.
165   //
166   // Note: similar approach is used for instruction scheduling (if it is turned on for the target):
167   // by default HScheduler::IsSchedulable returns false for a particular HVecOperation.
168   // HScheduler${ARCH}::IsSchedulable can be overridden to return true for an instruction (see
169   // scheduler_arm64.h for example) if it is safe to schedule it; in this case one *must* also
170   // look at/update HScheduler${ARCH}::IsSchedulingBarrier for this instruction.
171   //
172   // Note: For newly introduced vector instructions HScheduler${ARCH}::IsSchedulingBarrier must be
173   // altered to return true if the instruction might reside outside the SIMD loop body since SIMD
174   // registers are not kept alive across vector loop boundaries (yet).
CanBeMoved()175   bool CanBeMoved() const override { return false; }
176 
177   // Tests if all data of a vector node (vector length and packed type) is equal.
178   // Each concrete implementation that adds more fields should test equality of
179   // those fields in its own method *and* call all super methods.
InstructionDataEquals(const HInstruction * other)180   bool InstructionDataEquals(const HInstruction* other) const override {
181     DCHECK(other->IsVecOperation());
182     const HVecOperation* o = other->AsVecOperation();
183     return GetVectorLength() == o->GetVectorLength() && GetPackedType() == o->GetPackedType();
184   }
185 
186   // Maps an integral type to the same-size signed type and leaves other types alone.
ToSignedType(DataType::Type type)187   static DataType::Type ToSignedType(DataType::Type type) {
188     switch (type) {
189       case DataType::Type::kBool:  // 1-byte storage unit
190       case DataType::Type::kUint8:
191         return DataType::Type::kInt8;
192       case DataType::Type::kUint16:
193         return DataType::Type::kInt16;
194       default:
195         DCHECK(type != DataType::Type::kVoid && type != DataType::Type::kReference) << type;
196         return type;
197     }
198   }
199 
200   // Maps an integral type to the same-size unsigned type and leaves other types alone.
ToUnsignedType(DataType::Type type)201   static DataType::Type ToUnsignedType(DataType::Type type) {
202     switch (type) {
203       case DataType::Type::kBool:  // 1-byte storage unit
204       case DataType::Type::kInt8:
205         return DataType::Type::kUint8;
206       case DataType::Type::kInt16:
207         return DataType::Type::kUint16;
208       default:
209         DCHECK(type != DataType::Type::kVoid && type != DataType::Type::kReference) << type;
210         return type;
211     }
212   }
213 
214   // Maps an integral type to the same-size (un)signed type. Leaves other types alone.
ToProperType(DataType::Type type,bool is_unsigned)215   static DataType::Type ToProperType(DataType::Type type, bool is_unsigned) {
216     return is_unsigned ? ToUnsignedType(type) : ToSignedType(type);
217   }
218 
219   // Helper method to determine if an instruction returns a SIMD value.
220   // TODO: This method is needed until we introduce SIMD as proper type.
ReturnsSIMDValue(HInstruction * instruction)221   static bool ReturnsSIMDValue(HInstruction* instruction) {
222     if (instruction->IsVecOperation()) {
223       return !instruction->IsVecExtractScalar();  // only scalar returning vec op
224     } else if (instruction->IsPhi()) {
225       // Vectorizer only uses Phis in reductions, so checking for a 2-way phi
226       // with a direct vector operand as second argument suffices.
227       return
228           instruction->GetType() == kSIMDType &&
229           instruction->InputCount() == 2 &&
230           instruction->InputAt(1)->IsVecOperation();
231     }
232     return false;
233   }
234 
235   DECLARE_ABSTRACT_INSTRUCTION(VecOperation);
236 
237  protected:
238   // Additional packed bits.
239   static constexpr size_t kPredicationKind = HInstruction::kNumberOfGenericPackedBits;
240   static constexpr size_t kPredicationKindSize =
241       MinimumBitsToStore(static_cast<size_t>(PredicationKind::kLast));
242   static constexpr size_t kFieldPackedType = kPredicationKind + kPredicationKindSize;
243   static constexpr size_t kFieldPackedTypeSize =
244       MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
245   static constexpr size_t kNumberOfVectorOpPackedBits = kFieldPackedType + kFieldPackedTypeSize;
246   static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
247   using PackedTypeField = BitField<DataType::Type, kFieldPackedType, kFieldPackedTypeSize>;
248   using PredicationKindField = BitField<PredicationKind, kPredicationKind, kPredicationKindSize>;
249 
250   DEFAULT_COPY_CONSTRUCTOR(VecOperation);
251 
252  private:
253   const size_t vector_length_;
254 };
255 
256 // Abstraction of a unary vector operation.
257 class HVecUnaryOperation : public HVecOperation {
258  public:
HVecUnaryOperation(InstructionKind kind,ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)259   HVecUnaryOperation(InstructionKind kind,
260                      ArenaAllocator* allocator,
261                      HInstruction* input,
262                      DataType::Type packed_type,
263                      size_t vector_length,
264                      uint32_t dex_pc)
265       : HVecOperation(kind,
266                       allocator,
267                       packed_type,
268                       SideEffects::None(),
269                       /* number_of_inputs= */ 1,
270                       vector_length,
271                       dex_pc) {
272     SetRawInputAt(0, input);
273   }
274 
GetInput()275   HInstruction* GetInput() const { return InputAt(0); }
276 
277   DECLARE_ABSTRACT_INSTRUCTION(VecUnaryOperation);
278 
279  protected:
280   DEFAULT_COPY_CONSTRUCTOR(VecUnaryOperation);
281 };
282 
283 // Abstraction of a binary vector operation.
284 class HVecBinaryOperation : public HVecOperation {
285  public:
HVecBinaryOperation(InstructionKind kind,ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)286   HVecBinaryOperation(InstructionKind kind,
287                       ArenaAllocator* allocator,
288                       HInstruction* left,
289                       HInstruction* right,
290                       DataType::Type packed_type,
291                       size_t vector_length,
292                       uint32_t dex_pc)
293       : HVecOperation(kind,
294                       allocator,
295                       packed_type,
296                       SideEffects::None(),
297                       /* number_of_inputs= */ 2,
298                       vector_length,
299                       dex_pc) {
300     SetRawInputAt(0, left);
301     SetRawInputAt(1, right);
302   }
303 
GetLeft()304   HInstruction* GetLeft() const { return InputAt(0); }
GetRight()305   HInstruction* GetRight() const { return InputAt(1); }
306 
307   DECLARE_ABSTRACT_INSTRUCTION(VecBinaryOperation);
308 
309  protected:
310   DEFAULT_COPY_CONSTRUCTOR(VecBinaryOperation);
311 };
312 
313 // Abstraction of a vector operation that references memory, with an alignment.
314 // The Android runtime guarantees elements have at least natural alignment.
315 class HVecMemoryOperation : public HVecOperation {
316  public:
HVecMemoryOperation(InstructionKind kind,ArenaAllocator * allocator,DataType::Type packed_type,SideEffects side_effects,size_t number_of_inputs,size_t vector_length,uint32_t dex_pc)317   HVecMemoryOperation(InstructionKind kind,
318                       ArenaAllocator* allocator,
319                       DataType::Type packed_type,
320                       SideEffects side_effects,
321                       size_t number_of_inputs,
322                       size_t vector_length,
323                       uint32_t dex_pc)
324       : HVecOperation(kind,
325                       allocator,
326                       packed_type,
327                       side_effects,
328                       number_of_inputs,
329                       vector_length,
330                       dex_pc),
331         alignment_(DataType::Size(packed_type), 0) {
332     DCHECK_GE(number_of_inputs, 2u);
333   }
334 
SetAlignment(Alignment alignment)335   void SetAlignment(Alignment alignment) { alignment_ = alignment; }
336 
GetAlignment()337   Alignment GetAlignment() const { return alignment_; }
338 
GetArray()339   HInstruction* GetArray() const { return InputAt(0); }
GetIndex()340   HInstruction* GetIndex() const { return InputAt(1); }
341 
InstructionDataEquals(const HInstruction * other)342   bool InstructionDataEquals(const HInstruction* other) const override {
343     DCHECK(other->IsVecMemoryOperation());
344     const HVecMemoryOperation* o = other->AsVecMemoryOperation();
345     return HVecOperation::InstructionDataEquals(o) && GetAlignment() == o->GetAlignment();
346   }
347 
348   DECLARE_ABSTRACT_INSTRUCTION(VecMemoryOperation);
349 
350  protected:
351   DEFAULT_COPY_CONSTRUCTOR(VecMemoryOperation);
352 
353  private:
354   Alignment alignment_;
355 };
356 
357 // Packed type consistency checker ("same vector length" integral types may mix freely).
358 // Tests relaxed type consistency in which packed same-size integral types can co-exist,
359 // but other type mixes are an error.
HasConsistentPackedTypes(HInstruction * input,DataType::Type type)360 inline static bool HasConsistentPackedTypes(HInstruction* input, DataType::Type type) {
361   if (input->IsPhi()) {
362     return input->GetType() == HVecOperation::kSIMDType;  // carries SIMD
363   }
364   DCHECK(input->IsVecOperation());
365   DataType::Type input_type = input->AsVecOperation()->GetPackedType();
366   DCHECK_EQ(HVecOperation::ToUnsignedType(input_type) == HVecOperation::ToUnsignedType(type),
367             HVecOperation::ToSignedType(input_type) == HVecOperation::ToSignedType(type));
368   return HVecOperation::ToSignedType(input_type) == HVecOperation::ToSignedType(type);
369 }
370 
371 //
372 // Definitions of concrete unary vector operations in HIR.
373 //
374 
375 // Replicates the given scalar into a vector,
376 // viz. replicate(x) = [ x, .. , x ].
377 class HVecReplicateScalar final : public HVecUnaryOperation {
378  public:
HVecReplicateScalar(ArenaAllocator * allocator,HInstruction * scalar,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)379   HVecReplicateScalar(ArenaAllocator* allocator,
380                       HInstruction* scalar,
381                       DataType::Type packed_type,
382                       size_t vector_length,
383                       uint32_t dex_pc)
384       : HVecUnaryOperation(
385             kVecReplicateScalar, allocator, scalar, packed_type, vector_length, dex_pc) {
386     DCHECK(!ReturnsSIMDValue(scalar));
387   }
388 
389   // A replicate needs to stay in place, since SIMD registers are not
390   // kept alive across vector loop boundaries (yet).
CanBeMoved()391   bool CanBeMoved() const override { return false; }
392 
393   DECLARE_INSTRUCTION(VecReplicateScalar);
394 
395  protected:
396   DEFAULT_COPY_CONSTRUCTOR(VecReplicateScalar);
397 };
398 
399 // Extracts a particular scalar from the given vector,
400 // viz. extract[ x1, .. , xn ] = x_i.
401 //
402 // TODO: for now only i == 1 case supported.
403 class HVecExtractScalar final : public HVecUnaryOperation {
404  public:
HVecExtractScalar(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,size_t index,uint32_t dex_pc)405   HVecExtractScalar(ArenaAllocator* allocator,
406                     HInstruction* input,
407                     DataType::Type packed_type,
408                     size_t vector_length,
409                     size_t index,
410                     uint32_t dex_pc)
411       : HVecUnaryOperation(
412             kVecExtractScalar, allocator, input, packed_type, vector_length, dex_pc) {
413     DCHECK(HasConsistentPackedTypes(input, packed_type));
414     DCHECK_LT(index, vector_length);
415     DCHECK_EQ(index, 0u);
416     // Yields a single component in the vector.
417     // Overrides the kSIMDType set by the VecOperation constructor.
418     SetPackedField<TypeField>(packed_type);
419   }
420 
421   // An extract needs to stay in place, since SIMD registers are not
422   // kept alive across vector loop boundaries (yet).
CanBeMoved()423   bool CanBeMoved() const override { return false; }
424 
425   DECLARE_INSTRUCTION(VecExtractScalar);
426 
427  protected:
428   DEFAULT_COPY_CONSTRUCTOR(VecExtractScalar);
429 };
430 
431 // Reduces the given vector into the first element as sum/min/max,
432 // viz. sum-reduce[ x1, .. , xn ] = [ y, ---- ], where y = sum xi
433 // and the "-" denotes "don't care" (implementation dependent).
434 class HVecReduce final : public HVecUnaryOperation {
435  public:
436   enum ReductionKind {
437     kSum = 1,
438     kMin = 2,
439     kMax = 3
440   };
441 
HVecReduce(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,ReductionKind reduction_kind,uint32_t dex_pc)442   HVecReduce(ArenaAllocator* allocator,
443              HInstruction* input,
444              DataType::Type packed_type,
445              size_t vector_length,
446              ReductionKind reduction_kind,
447              uint32_t dex_pc)
448       : HVecUnaryOperation(kVecReduce, allocator, input, packed_type, vector_length, dex_pc),
449         reduction_kind_(reduction_kind) {
450     DCHECK(HasConsistentPackedTypes(input, packed_type));
451   }
452 
GetReductionKind()453   ReductionKind GetReductionKind() const { return reduction_kind_; }
454 
CanBeMoved()455   bool CanBeMoved() const override { return true; }
456 
InstructionDataEquals(const HInstruction * other)457   bool InstructionDataEquals(const HInstruction* other) const override {
458     DCHECK(other->IsVecReduce());
459     const HVecReduce* o = other->AsVecReduce();
460     return HVecOperation::InstructionDataEquals(o) && GetReductionKind() == o->GetReductionKind();
461   }
462 
463   DECLARE_INSTRUCTION(VecReduce);
464 
465  protected:
466   DEFAULT_COPY_CONSTRUCTOR(VecReduce);
467 
468  private:
469   const ReductionKind reduction_kind_;
470 };
471 
472 // Converts every component in the vector,
473 // viz. cnv[ x1, .. , xn ]  = [ cnv(x1), .. , cnv(xn) ].
474 class HVecCnv final : public HVecUnaryOperation {
475  public:
HVecCnv(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)476   HVecCnv(ArenaAllocator* allocator,
477           HInstruction* input,
478           DataType::Type packed_type,
479           size_t vector_length,
480           uint32_t dex_pc)
481       : HVecUnaryOperation(kVecCnv, allocator, input, packed_type, vector_length, dex_pc) {
482     DCHECK(input->IsVecOperation());
483     DCHECK_NE(GetInputType(), GetResultType());  // actual convert
484   }
485 
GetInputType()486   DataType::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); }
GetResultType()487   DataType::Type GetResultType() const { return GetPackedType(); }
488 
CanBeMoved()489   bool CanBeMoved() const override { return true; }
490 
491   DECLARE_INSTRUCTION(VecCnv);
492 
493  protected:
494   DEFAULT_COPY_CONSTRUCTOR(VecCnv);
495 };
496 
497 // Negates every component in the vector,
498 // viz. neg[ x1, .. , xn ]  = [ -x1, .. , -xn ].
499 class HVecNeg final : public HVecUnaryOperation {
500  public:
HVecNeg(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)501   HVecNeg(ArenaAllocator* allocator,
502           HInstruction* input,
503           DataType::Type packed_type,
504           size_t vector_length,
505           uint32_t dex_pc)
506       : HVecUnaryOperation(kVecNeg, allocator, input, packed_type, vector_length, dex_pc) {
507     DCHECK(HasConsistentPackedTypes(input, packed_type));
508   }
509 
CanBeMoved()510   bool CanBeMoved() const override { return true; }
511 
512   DECLARE_INSTRUCTION(VecNeg);
513 
514  protected:
515   DEFAULT_COPY_CONSTRUCTOR(VecNeg);
516 };
517 
518 // Takes absolute value of every component in the vector,
519 // viz. abs[ x1, .. , xn ]  = [ |x1|, .. , |xn| ]
520 // for signed operand x.
521 class HVecAbs final : public HVecUnaryOperation {
522  public:
HVecAbs(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)523   HVecAbs(ArenaAllocator* allocator,
524           HInstruction* input,
525           DataType::Type packed_type,
526           size_t vector_length,
527           uint32_t dex_pc)
528       : HVecUnaryOperation(kVecAbs, allocator, input, packed_type, vector_length, dex_pc) {
529     DCHECK(HasConsistentPackedTypes(input, packed_type));
530   }
531 
CanBeMoved()532   bool CanBeMoved() const override { return true; }
533 
534   DECLARE_INSTRUCTION(VecAbs);
535 
536  protected:
537   DEFAULT_COPY_CONSTRUCTOR(VecAbs);
538 };
539 
540 // Bitwise- or boolean-nots every component in the vector,
541 // viz. not[ x1, .. , xn ]  = [ ~x1, .. , ~xn ], or
542 //      not[ x1, .. , xn ]  = [ !x1, .. , !xn ] for boolean.
543 class HVecNot final : public HVecUnaryOperation {
544  public:
HVecNot(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)545   HVecNot(ArenaAllocator* allocator,
546           HInstruction* input,
547           DataType::Type packed_type,
548           size_t vector_length,
549           uint32_t dex_pc)
550       : HVecUnaryOperation(kVecNot, allocator, input, packed_type, vector_length, dex_pc) {
551     DCHECK(input->IsVecOperation());
552   }
553 
CanBeMoved()554   bool CanBeMoved() const override { return true; }
555 
556   DECLARE_INSTRUCTION(VecNot);
557 
558  protected:
559   DEFAULT_COPY_CONSTRUCTOR(VecNot);
560 };
561 
562 //
563 // Definitions of concrete binary vector operations in HIR.
564 //
565 
566 // Adds every component in the two vectors,
567 // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 + y1, .. , xn + yn ].
568 class HVecAdd final : public HVecBinaryOperation {
569  public:
HVecAdd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)570   HVecAdd(ArenaAllocator* allocator,
571           HInstruction* left,
572           HInstruction* right,
573           DataType::Type packed_type,
574           size_t vector_length,
575           uint32_t dex_pc)
576       : HVecBinaryOperation(kVecAdd, allocator, left, right, packed_type, vector_length, dex_pc) {
577     DCHECK(HasConsistentPackedTypes(left, packed_type));
578     DCHECK(HasConsistentPackedTypes(right, packed_type));
579   }
580 
CanBeMoved()581   bool CanBeMoved() const override { return true; }
582 
583   DECLARE_INSTRUCTION(VecAdd);
584 
585  protected:
586   DEFAULT_COPY_CONSTRUCTOR(VecAdd);
587 };
588 
589 // Adds every component in the two vectors using saturation arithmetic,
590 // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 +_sat y1, .. , xn +_sat yn ]
591 // for either both signed or both unsigned operands x, y (reflected in packed_type).
592 class HVecSaturationAdd final : public HVecBinaryOperation {
593  public:
HVecSaturationAdd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)594   HVecSaturationAdd(ArenaAllocator* allocator,
595                     HInstruction* left,
596                     HInstruction* right,
597                     DataType::Type packed_type,
598                     size_t vector_length,
599                     uint32_t dex_pc)
600       : HVecBinaryOperation(
601           kVecSaturationAdd, allocator, left, right, packed_type, vector_length, dex_pc) {
602     DCHECK(HasConsistentPackedTypes(left, packed_type));
603     DCHECK(HasConsistentPackedTypes(right, packed_type));
604   }
605 
CanBeMoved()606   bool CanBeMoved() const override { return true; }
607 
608   DECLARE_INSTRUCTION(VecSaturationAdd);
609 
610  protected:
611   DEFAULT_COPY_CONSTRUCTOR(VecSaturationAdd);
612 };
613 
614 // Performs halving add on every component in the two vectors, viz.
615 // rounded   [ x1, .. , xn ] hradd [ y1, .. , yn ] = [ (x1 + y1 + 1) >> 1, .. , (xn + yn + 1) >> 1 ]
616 // truncated [ x1, .. , xn ] hadd  [ y1, .. , yn ] = [ (x1 + y1)     >> 1, .. , (xn + yn )    >> 1 ]
617 // for either both signed or both unsigned operands x, y (reflected in packed_type).
618 class HVecHalvingAdd final : public HVecBinaryOperation {
619  public:
HVecHalvingAdd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,bool is_rounded,uint32_t dex_pc)620   HVecHalvingAdd(ArenaAllocator* allocator,
621                  HInstruction* left,
622                  HInstruction* right,
623                  DataType::Type packed_type,
624                  size_t vector_length,
625                  bool is_rounded,
626                  uint32_t dex_pc)
627       : HVecBinaryOperation(
628             kVecHalvingAdd, allocator, left, right, packed_type, vector_length, dex_pc) {
629     DCHECK(HasConsistentPackedTypes(left, packed_type));
630     DCHECK(HasConsistentPackedTypes(right, packed_type));
631     SetPackedFlag<kFieldHAddIsRounded>(is_rounded);
632   }
633 
IsRounded()634   bool IsRounded() const { return GetPackedFlag<kFieldHAddIsRounded>(); }
635 
CanBeMoved()636   bool CanBeMoved() const override { return true; }
637 
InstructionDataEquals(const HInstruction * other)638   bool InstructionDataEquals(const HInstruction* other) const override {
639     DCHECK(other->IsVecHalvingAdd());
640     const HVecHalvingAdd* o = other->AsVecHalvingAdd();
641     return HVecOperation::InstructionDataEquals(o) && IsRounded() == o->IsRounded();
642   }
643 
644   DECLARE_INSTRUCTION(VecHalvingAdd);
645 
646  protected:
647   DEFAULT_COPY_CONSTRUCTOR(VecHalvingAdd);
648 
649  private:
650   // Additional packed bits.
651   static constexpr size_t kFieldHAddIsRounded = HVecOperation::kNumberOfVectorOpPackedBits;
652   static constexpr size_t kNumberOfHAddPackedBits = kFieldHAddIsRounded + 1;
653   static_assert(kNumberOfHAddPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
654 };
655 
656 // Subtracts every component in the two vectors,
657 // viz. [ x1, .. , xn ] - [ y1, .. , yn ] = [ x1 - y1, .. , xn - yn ].
658 class HVecSub final : public HVecBinaryOperation {
659  public:
HVecSub(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)660   HVecSub(ArenaAllocator* allocator,
661           HInstruction* left,
662           HInstruction* right,
663           DataType::Type packed_type,
664           size_t vector_length,
665           uint32_t dex_pc)
666       : HVecBinaryOperation(kVecSub, allocator, left, right, packed_type, vector_length, dex_pc) {
667     DCHECK(HasConsistentPackedTypes(left, packed_type));
668     DCHECK(HasConsistentPackedTypes(right, packed_type));
669   }
670 
CanBeMoved()671   bool CanBeMoved() const override { return true; }
672 
673   DECLARE_INSTRUCTION(VecSub);
674 
675  protected:
676   DEFAULT_COPY_CONSTRUCTOR(VecSub);
677 };
678 
679 // Subtracts every component in the two vectors using saturation arithmetic,
680 // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 -_sat y1, .. , xn -_sat yn ]
681 // for either both signed or both unsigned operands x, y (reflected in packed_type).
682 class HVecSaturationSub final : public HVecBinaryOperation {
683  public:
HVecSaturationSub(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)684   HVecSaturationSub(ArenaAllocator* allocator,
685                     HInstruction* left,
686                     HInstruction* right,
687                     DataType::Type packed_type,
688                     size_t vector_length,
689                     uint32_t dex_pc)
690       : HVecBinaryOperation(
691           kVecSaturationSub, allocator, left, right, packed_type, vector_length, dex_pc) {
692     DCHECK(HasConsistentPackedTypes(left, packed_type));
693     DCHECK(HasConsistentPackedTypes(right, packed_type));
694   }
695 
CanBeMoved()696   bool CanBeMoved() const override { return true; }
697 
698   DECLARE_INSTRUCTION(VecSaturationSub);
699 
700  protected:
701   DEFAULT_COPY_CONSTRUCTOR(VecSaturationSub);
702 };
703 
704 // Multiplies every component in the two vectors,
705 // viz. [ x1, .. , xn ] * [ y1, .. , yn ] = [ x1 * y1, .. , xn * yn ].
706 class HVecMul final : public HVecBinaryOperation {
707  public:
HVecMul(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)708   HVecMul(ArenaAllocator* allocator,
709           HInstruction* left,
710           HInstruction* right,
711           DataType::Type packed_type,
712           size_t vector_length,
713           uint32_t dex_pc)
714       : HVecBinaryOperation(kVecMul, allocator, left, right, packed_type, vector_length, dex_pc) {
715     DCHECK(HasConsistentPackedTypes(left, packed_type));
716     DCHECK(HasConsistentPackedTypes(right, packed_type));
717   }
718 
CanBeMoved()719   bool CanBeMoved() const override { return true; }
720 
721   DECLARE_INSTRUCTION(VecMul);
722 
723  protected:
724   DEFAULT_COPY_CONSTRUCTOR(VecMul);
725 };
726 
727 // Divides every component in the two vectors,
728 // viz. [ x1, .. , xn ] / [ y1, .. , yn ] = [ x1 / y1, .. , xn / yn ].
729 class HVecDiv final : public HVecBinaryOperation {
730  public:
HVecDiv(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)731   HVecDiv(ArenaAllocator* allocator,
732           HInstruction* left,
733           HInstruction* right,
734           DataType::Type packed_type,
735           size_t vector_length,
736           uint32_t dex_pc)
737       : HVecBinaryOperation(kVecDiv, allocator, left, right, packed_type, vector_length, dex_pc) {
738     DCHECK(HasConsistentPackedTypes(left, packed_type));
739     DCHECK(HasConsistentPackedTypes(right, packed_type));
740   }
741 
CanBeMoved()742   bool CanBeMoved() const override { return true; }
743 
744   DECLARE_INSTRUCTION(VecDiv);
745 
746  protected:
747   DEFAULT_COPY_CONSTRUCTOR(VecDiv);
748 };
749 
750 // Takes minimum of every component in the two vectors,
751 // viz. MIN( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ min(x1, y1), .. , min(xn, yn) ]
752 // for either both signed or both unsigned operands x, y (reflected in packed_type).
753 class HVecMin final : public HVecBinaryOperation {
754  public:
HVecMin(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)755   HVecMin(ArenaAllocator* allocator,
756           HInstruction* left,
757           HInstruction* right,
758           DataType::Type packed_type,
759           size_t vector_length,
760           uint32_t dex_pc)
761       : HVecBinaryOperation(kVecMin, allocator, left, right, packed_type, vector_length, dex_pc) {
762     DCHECK(HasConsistentPackedTypes(left, packed_type));
763     DCHECK(HasConsistentPackedTypes(right, packed_type));
764   }
765 
CanBeMoved()766   bool CanBeMoved() const override { return true; }
767 
768   DECLARE_INSTRUCTION(VecMin);
769 
770  protected:
771   DEFAULT_COPY_CONSTRUCTOR(VecMin);
772 };
773 
774 // Takes maximum of every component in the two vectors,
775 // viz. MAX( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ max(x1, y1), .. , max(xn, yn) ]
776 // for either both signed or both unsigned operands x, y (reflected in packed_type).
777 class HVecMax final : public HVecBinaryOperation {
778  public:
HVecMax(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)779   HVecMax(ArenaAllocator* allocator,
780           HInstruction* left,
781           HInstruction* right,
782           DataType::Type packed_type,
783           size_t vector_length,
784           uint32_t dex_pc)
785       : HVecBinaryOperation(kVecMax, allocator, left, right, packed_type, vector_length, dex_pc) {
786     DCHECK(HasConsistentPackedTypes(left, packed_type));
787     DCHECK(HasConsistentPackedTypes(right, packed_type));
788   }
789 
CanBeMoved()790   bool CanBeMoved() const override { return true; }
791 
792   DECLARE_INSTRUCTION(VecMax);
793 
794  protected:
795   DEFAULT_COPY_CONSTRUCTOR(VecMax);
796 };
797 
798 // Bitwise-ands every component in the two vectors,
799 // viz. [ x1, .. , xn ] & [ y1, .. , yn ] = [ x1 & y1, .. , xn & yn ].
800 class HVecAnd final : public HVecBinaryOperation {
801  public:
HVecAnd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)802   HVecAnd(ArenaAllocator* allocator,
803           HInstruction* left,
804           HInstruction* right,
805           DataType::Type packed_type,
806           size_t vector_length,
807           uint32_t dex_pc)
808       : HVecBinaryOperation(kVecAnd, allocator, left, right, packed_type, vector_length, dex_pc) {
809     DCHECK(left->IsVecOperation() && right->IsVecOperation());
810   }
811 
CanBeMoved()812   bool CanBeMoved() const override { return true; }
813 
814   DECLARE_INSTRUCTION(VecAnd);
815 
816  protected:
817   DEFAULT_COPY_CONSTRUCTOR(VecAnd);
818 };
819 
820 // Bitwise-and-nots every component in the two vectors,
821 // viz. [ x1, .. , xn ] and-not [ y1, .. , yn ] = [ ~x1 & y1, .. , ~xn & yn ].
822 class HVecAndNot final : public HVecBinaryOperation {
823  public:
HVecAndNot(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)824   HVecAndNot(ArenaAllocator* allocator,
825              HInstruction* left,
826              HInstruction* right,
827              DataType::Type packed_type,
828              size_t vector_length,
829              uint32_t dex_pc)
830          : HVecBinaryOperation(
831                kVecAndNot, allocator, left, right, packed_type, vector_length, dex_pc) {
832     DCHECK(left->IsVecOperation() && right->IsVecOperation());
833   }
834 
CanBeMoved()835   bool CanBeMoved() const override { return true; }
836 
837   DECLARE_INSTRUCTION(VecAndNot);
838 
839  protected:
840   DEFAULT_COPY_CONSTRUCTOR(VecAndNot);
841 };
842 
843 // Bitwise-ors every component in the two vectors,
844 // viz. [ x1, .. , xn ] | [ y1, .. , yn ] = [ x1 | y1, .. , xn | yn ].
845 class HVecOr final : public HVecBinaryOperation {
846  public:
HVecOr(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)847   HVecOr(ArenaAllocator* allocator,
848          HInstruction* left,
849          HInstruction* right,
850          DataType::Type packed_type,
851          size_t vector_length,
852          uint32_t dex_pc)
853       : HVecBinaryOperation(kVecOr, allocator, left, right, packed_type, vector_length, dex_pc) {
854     DCHECK(left->IsVecOperation() && right->IsVecOperation());
855   }
856 
CanBeMoved()857   bool CanBeMoved() const override { return true; }
858 
859   DECLARE_INSTRUCTION(VecOr);
860 
861  protected:
862   DEFAULT_COPY_CONSTRUCTOR(VecOr);
863 };
864 
865 // Bitwise-xors every component in the two vectors,
866 // viz. [ x1, .. , xn ] ^ [ y1, .. , yn ] = [ x1 ^ y1, .. , xn ^ yn ].
867 class HVecXor final : public HVecBinaryOperation {
868  public:
HVecXor(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)869   HVecXor(ArenaAllocator* allocator,
870           HInstruction* left,
871           HInstruction* right,
872           DataType::Type packed_type,
873           size_t vector_length,
874           uint32_t dex_pc)
875       : HVecBinaryOperation(kVecXor, allocator, left, right, packed_type, vector_length, dex_pc) {
876     DCHECK(left->IsVecOperation() && right->IsVecOperation());
877   }
878 
CanBeMoved()879   bool CanBeMoved() const override { return true; }
880 
881   DECLARE_INSTRUCTION(VecXor);
882 
883  protected:
884   DEFAULT_COPY_CONSTRUCTOR(VecXor);
885 };
886 
887 // Logically shifts every component in the vector left by the given distance,
888 // viz. [ x1, .. , xn ] << d = [ x1 << d, .. , xn << d ].
889 class HVecShl final : public HVecBinaryOperation {
890  public:
HVecShl(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)891   HVecShl(ArenaAllocator* allocator,
892           HInstruction* left,
893           HInstruction* right,
894           DataType::Type packed_type,
895           size_t vector_length,
896           uint32_t dex_pc)
897       : HVecBinaryOperation(kVecShl, allocator, left, right, packed_type, vector_length, dex_pc) {
898     DCHECK(HasConsistentPackedTypes(left, packed_type));
899   }
900 
CanBeMoved()901   bool CanBeMoved() const override { return true; }
902 
903   DECLARE_INSTRUCTION(VecShl);
904 
905  protected:
906   DEFAULT_COPY_CONSTRUCTOR(VecShl);
907 };
908 
909 // Arithmetically shifts every component in the vector right by the given distance,
910 // viz. [ x1, .. , xn ] >> d = [ x1 >> d, .. , xn >> d ].
911 class HVecShr final : public HVecBinaryOperation {
912  public:
HVecShr(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)913   HVecShr(ArenaAllocator* allocator,
914           HInstruction* left,
915           HInstruction* right,
916           DataType::Type packed_type,
917           size_t vector_length,
918           uint32_t dex_pc)
919       : HVecBinaryOperation(kVecShr, allocator, left, right, packed_type, vector_length, dex_pc) {
920     DCHECK(HasConsistentPackedTypes(left, packed_type));
921   }
922 
CanBeMoved()923   bool CanBeMoved() const override { return true; }
924 
925   DECLARE_INSTRUCTION(VecShr);
926 
927  protected:
928   DEFAULT_COPY_CONSTRUCTOR(VecShr);
929 };
930 
931 // Logically shifts every component in the vector right by the given distance,
932 // viz. [ x1, .. , xn ] >>> d = [ x1 >>> d, .. , xn >>> d ].
933 class HVecUShr final : public HVecBinaryOperation {
934  public:
HVecUShr(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)935   HVecUShr(ArenaAllocator* allocator,
936            HInstruction* left,
937            HInstruction* right,
938            DataType::Type packed_type,
939            size_t vector_length,
940            uint32_t dex_pc)
941       : HVecBinaryOperation(kVecUShr, allocator, left, right, packed_type, vector_length, dex_pc) {
942     DCHECK(HasConsistentPackedTypes(left, packed_type));
943   }
944 
CanBeMoved()945   bool CanBeMoved() const override { return true; }
946 
947   DECLARE_INSTRUCTION(VecUShr);
948 
949  protected:
950   DEFAULT_COPY_CONSTRUCTOR(VecUShr);
951 };
952 
953 //
954 // Definitions of concrete miscellaneous vector operations in HIR.
955 //
956 
957 // Assigns the given scalar elements to a vector,
958 // viz. set( array(x1, .. , xn) ) = [ x1, .. ,            xn ] if n == m,
959 //      set( array(x1, .. , xm) ) = [ x1, .. , xm, 0, .. , 0 ] if m <  n.
960 class HVecSetScalars final : public HVecOperation {
961  public:
HVecSetScalars(ArenaAllocator * allocator,HInstruction * scalars[],DataType::Type packed_type,size_t vector_length,size_t number_of_scalars,uint32_t dex_pc)962   HVecSetScalars(ArenaAllocator* allocator,
963                  HInstruction* scalars[],
964                  DataType::Type packed_type,
965                  size_t vector_length,
966                  size_t number_of_scalars,
967                  uint32_t dex_pc)
968       : HVecOperation(kVecSetScalars,
969                       allocator,
970                       packed_type,
971                       SideEffects::None(),
972                       number_of_scalars,
973                       vector_length,
974                       dex_pc) {
975     for (size_t i = 0; i < number_of_scalars; i++) {
976       DCHECK(!ReturnsSIMDValue(scalars[i]));
977       SetRawInputAt(0, scalars[i]);
978     }
979   }
980 
981   // Setting scalars needs to stay in place, since SIMD registers are not
982   // kept alive across vector loop boundaries (yet).
CanBeMoved()983   bool CanBeMoved() const override { return false; }
984 
985   DECLARE_INSTRUCTION(VecSetScalars);
986 
987  protected:
988   DEFAULT_COPY_CONSTRUCTOR(VecSetScalars);
989 };
990 
991 // Multiplies every component in the two vectors, adds the result vector to the accumulator vector,
992 // viz. [ a1, .. , an ] + [ x1, .. , xn ] * [ y1, .. , yn ] = [ a1 + x1 * y1, .. , an + xn * yn ].
993 // For floating point types, Java rounding behavior must be preserved; the products are rounded to
994 // the proper precision before being added. "Fused" multiply-add operations available on several
995 // architectures are not usable since they would violate Java language rules.
996 class HVecMultiplyAccumulate final : public HVecOperation {
997  public:
HVecMultiplyAccumulate(ArenaAllocator * allocator,InstructionKind op,HInstruction * accumulator,HInstruction * mul_left,HInstruction * mul_right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)998   HVecMultiplyAccumulate(ArenaAllocator* allocator,
999                          InstructionKind op,
1000                          HInstruction* accumulator,
1001                          HInstruction* mul_left,
1002                          HInstruction* mul_right,
1003                          DataType::Type packed_type,
1004                          size_t vector_length,
1005                          uint32_t dex_pc)
1006       : HVecOperation(kVecMultiplyAccumulate,
1007                       allocator,
1008                       packed_type,
1009                       SideEffects::None(),
1010                       /* number_of_inputs= */ 3,
1011                       vector_length,
1012                       dex_pc),
1013         op_kind_(op) {
1014     DCHECK(op == InstructionKind::kAdd || op == InstructionKind::kSub);
1015     DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
1016     DCHECK(HasConsistentPackedTypes(mul_left, packed_type));
1017     DCHECK(HasConsistentPackedTypes(mul_right, packed_type));
1018     // Remove the following if we add an architecture that supports floating point multiply-add
1019     // with Java-compatible rounding.
1020     DCHECK(DataType::IsIntegralType(packed_type));
1021     SetRawInputAt(0, accumulator);
1022     SetRawInputAt(1, mul_left);
1023     SetRawInputAt(2, mul_right);
1024   }
1025 
CanBeMoved()1026   bool CanBeMoved() const override { return true; }
1027 
InstructionDataEquals(const HInstruction * other)1028   bool InstructionDataEquals(const HInstruction* other) const override {
1029     DCHECK(other->IsVecMultiplyAccumulate());
1030     const HVecMultiplyAccumulate* o = other->AsVecMultiplyAccumulate();
1031     return HVecOperation::InstructionDataEquals(o) && GetOpKind() == o->GetOpKind();
1032   }
1033 
GetOpKind()1034   InstructionKind GetOpKind() const { return op_kind_; }
1035 
1036   DECLARE_INSTRUCTION(VecMultiplyAccumulate);
1037 
1038  protected:
1039   DEFAULT_COPY_CONSTRUCTOR(VecMultiplyAccumulate);
1040 
1041  private:
1042   // Indicates if this is a MADD or MSUB.
1043   const InstructionKind op_kind_;
1044 };
1045 
1046 // Takes the absolute difference of two vectors, and adds the results to
1047 // same-precision or wider-precision components in the accumulator,
1048 // viz. SAD([ a1, .. , am ], [ x1, .. , xn ], [ y1, .. , yn ]) =
1049 //          [ a1 + sum abs(xi-yi), .. , am + sum abs(xj-yj) ],
1050 //      for m <= n, non-overlapping sums, and signed operands x, y.
1051 class HVecSADAccumulate final : public HVecOperation {
1052  public:
HVecSADAccumulate(ArenaAllocator * allocator,HInstruction * accumulator,HInstruction * sad_left,HInstruction * sad_right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)1053   HVecSADAccumulate(ArenaAllocator* allocator,
1054                     HInstruction* accumulator,
1055                     HInstruction* sad_left,
1056                     HInstruction* sad_right,
1057                     DataType::Type packed_type,
1058                     size_t vector_length,
1059                     uint32_t dex_pc)
1060       : HVecOperation(kVecSADAccumulate,
1061                       allocator,
1062                       packed_type,
1063                       SideEffects::None(),
1064                       /* number_of_inputs= */ 3,
1065                       vector_length,
1066                       dex_pc) {
1067     DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
1068     DCHECK(sad_left->IsVecOperation());
1069     DCHECK(sad_right->IsVecOperation());
1070     DCHECK_EQ(ToSignedType(sad_left->AsVecOperation()->GetPackedType()),
1071               ToSignedType(sad_right->AsVecOperation()->GetPackedType()));
1072     SetRawInputAt(0, accumulator);
1073     SetRawInputAt(1, sad_left);
1074     SetRawInputAt(2, sad_right);
1075   }
1076 
1077   DECLARE_INSTRUCTION(VecSADAccumulate);
1078 
1079  protected:
1080   DEFAULT_COPY_CONSTRUCTOR(VecSADAccumulate);
1081 };
1082 
1083 // Performs dot product of two vectors and adds the result to wider precision components in
1084 // the accumulator.
1085 //
1086 // viz. DOT_PRODUCT([ a1, .. , am], [ x1, .. , xn ], [ y1, .. , yn ]) =
1087 //                  [ a1 + sum(xi * yi), .. , am + sum(xj * yj) ],
1088 //      for m <= n, non-overlapping sums,
1089 //      for either both signed or both unsigned operands x, y.
1090 //
1091 // Notes:
1092 //   - packed type reflects the type of sum reduction, not the type of the operands.
1093 //   - IsZeroExtending() is used to determine the kind of signed/zero extension to be
1094 //     performed for the operands.
1095 //
1096 // TODO: Support types other than kInt32 for packed type.
1097 class HVecDotProd final : public HVecOperation {
1098  public:
HVecDotProd(ArenaAllocator * allocator,HInstruction * accumulator,HInstruction * left,HInstruction * right,DataType::Type packed_type,bool is_zero_extending,size_t vector_length,uint32_t dex_pc)1099   HVecDotProd(ArenaAllocator* allocator,
1100               HInstruction* accumulator,
1101               HInstruction* left,
1102               HInstruction* right,
1103               DataType::Type packed_type,
1104               bool is_zero_extending,
1105               size_t vector_length,
1106               uint32_t dex_pc)
1107     : HVecOperation(kVecDotProd,
1108                     allocator,
1109                     packed_type,
1110                     SideEffects::None(),
1111                     /* number_of_inputs= */ 3,
1112                     vector_length,
1113                     dex_pc) {
1114     DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
1115     DCHECK(DataType::IsIntegralType(packed_type));
1116     DCHECK(left->IsVecOperation());
1117     DCHECK(right->IsVecOperation());
1118     DCHECK_EQ(ToSignedType(left->AsVecOperation()->GetPackedType()),
1119               ToSignedType(right->AsVecOperation()->GetPackedType()));
1120     SetRawInputAt(0, accumulator);
1121     SetRawInputAt(1, left);
1122     SetRawInputAt(2, right);
1123     SetPackedFlag<kFieldHDotProdIsZeroExtending>(is_zero_extending);
1124   }
1125 
IsZeroExtending()1126   bool IsZeroExtending() const { return GetPackedFlag<kFieldHDotProdIsZeroExtending>(); }
1127 
CanBeMoved()1128   bool CanBeMoved() const override { return true; }
1129 
1130   DECLARE_INSTRUCTION(VecDotProd);
1131 
1132  protected:
1133   DEFAULT_COPY_CONSTRUCTOR(VecDotProd);
1134 
1135  private:
1136   // Additional packed bits.
1137   static constexpr size_t kFieldHDotProdIsZeroExtending =
1138       HVecOperation::kNumberOfVectorOpPackedBits;
1139   static constexpr size_t kNumberOfHDotProdPackedBits = kFieldHDotProdIsZeroExtending + 1;
1140   static_assert(kNumberOfHDotProdPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
1141 };
1142 
1143 // Loads a vector from memory, viz. load(mem, 1)
1144 // yield the vector [ mem(1), .. , mem(n) ].
1145 class HVecLoad final : public HVecMemoryOperation {
1146  public:
HVecLoad(ArenaAllocator * allocator,HInstruction * base,HInstruction * index,DataType::Type packed_type,SideEffects side_effects,size_t vector_length,bool is_string_char_at,uint32_t dex_pc)1147   HVecLoad(ArenaAllocator* allocator,
1148            HInstruction* base,
1149            HInstruction* index,
1150            DataType::Type packed_type,
1151            SideEffects side_effects,
1152            size_t vector_length,
1153            bool is_string_char_at,
1154            uint32_t dex_pc)
1155       : HVecMemoryOperation(kVecLoad,
1156                             allocator,
1157                             packed_type,
1158                             side_effects,
1159                             /* number_of_inputs= */ 2,
1160                             vector_length,
1161                             dex_pc) {
1162     SetRawInputAt(0, base);
1163     SetRawInputAt(1, index);
1164     SetPackedFlag<kFieldIsStringCharAt>(is_string_char_at);
1165   }
1166 
IsStringCharAt()1167   bool IsStringCharAt() const { return GetPackedFlag<kFieldIsStringCharAt>(); }
1168 
CanBeMoved()1169   bool CanBeMoved() const override { return true; }
1170 
InstructionDataEquals(const HInstruction * other)1171   bool InstructionDataEquals(const HInstruction* other) const override {
1172     DCHECK(other->IsVecLoad());
1173     const HVecLoad* o = other->AsVecLoad();
1174     return HVecMemoryOperation::InstructionDataEquals(o) && IsStringCharAt() == o->IsStringCharAt();
1175   }
1176 
1177   DECLARE_INSTRUCTION(VecLoad);
1178 
1179  protected:
1180   DEFAULT_COPY_CONSTRUCTOR(VecLoad);
1181 
1182  private:
1183   // Additional packed bits.
1184   static constexpr size_t kFieldIsStringCharAt = HVecOperation::kNumberOfVectorOpPackedBits;
1185   static constexpr size_t kNumberOfVecLoadPackedBits = kFieldIsStringCharAt + 1;
1186   static_assert(kNumberOfVecLoadPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
1187 };
1188 
1189 // Stores a vector to memory, viz. store(m, 1, [x1, .. , xn] )
1190 // sets mem(1) = x1, .. , mem(n) = xn.
1191 class HVecStore final : public HVecMemoryOperation {
1192  public:
HVecStore(ArenaAllocator * allocator,HInstruction * base,HInstruction * index,HInstruction * value,DataType::Type packed_type,SideEffects side_effects,size_t vector_length,uint32_t dex_pc)1193   HVecStore(ArenaAllocator* allocator,
1194             HInstruction* base,
1195             HInstruction* index,
1196             HInstruction* value,
1197             DataType::Type packed_type,
1198             SideEffects side_effects,
1199             size_t vector_length,
1200             uint32_t dex_pc)
1201       : HVecMemoryOperation(kVecStore,
1202                             allocator,
1203                             packed_type,
1204                             side_effects,
1205                             /* number_of_inputs= */ 3,
1206                             vector_length,
1207                             dex_pc) {
1208     DCHECK(HasConsistentPackedTypes(value, packed_type));
1209     SetRawInputAt(0, base);
1210     SetRawInputAt(1, index);
1211     SetRawInputAt(2, value);
1212   }
1213 
1214   // A store needs to stay in place.
CanBeMoved()1215   bool CanBeMoved() const override { return false; }
1216 
GetValue()1217   HInstruction* GetValue() const { return InputAt(2); }
1218 
1219   DECLARE_INSTRUCTION(VecStore);
1220 
1221  protected:
1222   DEFAULT_COPY_CONSTRUCTOR(VecStore)
1223 };
1224 
1225 //
1226 // 'Predicate-setting' instructions.
1227 //
1228 
1229 // An abstract class for instructions for which the output value is a vector predicate -
1230 // a special kind of vector value:
1231 //
1232 //    viz. [ p1, .. , pn ], where p_i is from { 0, 1 }.
1233 //
1234 // A VecOperation OP executes the same operation (e.g. ADD) on multiple elements of the vector.
1235 // It can be either unpredicated (operation is done on ALL of the elements) or predicated (only
1236 // on SOME elements, determined by a special extra input - vector predicate).
1237 // Implementations can vary depending on the ISA; the general idea is that for each element of the
1238 // regular vector a vector predicate has a corresponding element with either 0 or 1.
1239 // The value determines whether a vector element will be involved in OP calculations or not
1240 // (active or inactive). A vector predicate is referred as governing one if it is used to
1241 // control the execution of a predicated instruction.
1242 //
1243 // Note: vector predicate value type is introduced alongside existing vectors of booleans and
1244 // vectors of bytes to reflect their special semantics.
1245 //
1246 // TODO: we could introduce SIMD types in HIR.
1247 class HVecPredSetOperation : public HVecOperation {
1248  public:
1249   // A vector predicate-setting operation looks like a Int64 location.
1250   // TODO: we could introduce vector types in HIR.
1251   static constexpr DataType::Type kSIMDPredType = DataType::Type::kInt64;
1252 
HVecPredSetOperation(InstructionKind kind,ArenaAllocator * allocator,DataType::Type packed_type,SideEffects side_effects,size_t number_of_inputs,size_t vector_length,uint32_t dex_pc)1253   HVecPredSetOperation(InstructionKind kind,
1254                        ArenaAllocator* allocator,
1255                        DataType::Type packed_type,
1256                        SideEffects side_effects,
1257                        size_t number_of_inputs,
1258                        size_t vector_length,
1259                        uint32_t dex_pc)
1260       : HVecOperation(kind,
1261                       allocator,
1262                       packed_type,
1263                       side_effects,
1264                       number_of_inputs,
1265                       vector_length,
1266                       dex_pc) {
1267     // Overrides the kSIMDType set by the VecOperation constructor.
1268     SetPackedField<TypeField>(kSIMDPredType);
1269   }
1270 
CanBeMoved()1271   bool CanBeMoved() const override { return true; }
1272 
1273   DECLARE_ABSTRACT_INSTRUCTION(VecPredSetOperation);
1274 
1275  protected:
1276   DEFAULT_COPY_CONSTRUCTOR(VecPredSetOperation);
1277 };
1278 
1279 // Sets all the vector predicate elements as active or inactive.
1280 //
1281 // viz. [ p1, .. , pn ]  = [ val, .. , val ] where val is from { 1, 0 }.
1282 class HVecPredSetAll final : public HVecPredSetOperation {
1283  public:
HVecPredSetAll(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)1284   HVecPredSetAll(ArenaAllocator* allocator,
1285                  HInstruction* input,
1286                  DataType::Type packed_type,
1287                  size_t vector_length,
1288                  uint32_t dex_pc) :
1289       HVecPredSetOperation(kVecPredSetAll,
1290                            allocator,
1291                            packed_type,
1292                            SideEffects::None(),
1293                            /* number_of_inputs= */ 1,
1294                            vector_length,
1295                            dex_pc) {
1296     DCHECK(input->IsIntConstant());
1297     SetRawInputAt(0, input);
1298     MarkEmittedAtUseSite();
1299   }
1300 
1301   // Having governing predicate doesn't make sense for set all TRUE/FALSE instruction.
MustBePredicatedInPredicatedSIMDMode()1302   bool MustBePredicatedInPredicatedSIMDMode() override { return false; }
1303 
IsSetTrue()1304   bool IsSetTrue() const { return InputAt(0)->AsIntConstant()->IsTrue(); }
1305 
1306   // Vector predicates are not kept alive across vector loop boundaries.
CanBeMoved()1307   bool CanBeMoved() const override { return false; }
1308 
1309   DECLARE_INSTRUCTION(VecPredSetAll);
1310 
1311  protected:
1312   DEFAULT_COPY_CONSTRUCTOR(VecPredSetAll);
1313 };
1314 
1315 //
1316 // Arm64 SVE-specific instructions.
1317 //
1318 // Classes of instructions which are specific to Arm64 SVE (though could be adopted
1319 // by other targets, possibly being lowered to a number of ISA instructions) and
1320 // implement SIMD loop predicated execution idiom.
1321 //
1322 
1323 // Takes two scalar values x and y, creates a vector S: s(n) = x + n, compares (OP) each s(n)
1324 // with y and set the corresponding element of the predicate register to the result of the
1325 // comparison.
1326 //
1327 // viz. [ p1, .. , pn ]  = [ x OP y , (x + 1) OP y, .. , (x + n) OP y ] where OP is CondKind
1328 // condition.
1329 class HVecPredWhile final : public HVecPredSetOperation {
1330  public:
1331   enum class CondKind {
1332     kLE,   // signed less than or equal.
1333     kLO,   // unsigned lower.
1334     kLS,   // unsigned lower or same.
1335     kLT,   // signed less.
1336     kLast = kLT,
1337   };
1338 
HVecPredWhile(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,CondKind cond,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)1339   HVecPredWhile(ArenaAllocator* allocator,
1340                 HInstruction* left,
1341                 HInstruction* right,
1342                 CondKind cond,
1343                 DataType::Type packed_type,
1344                 size_t vector_length,
1345                 uint32_t dex_pc) :
1346       HVecPredSetOperation(kVecPredWhile,
1347                            allocator,
1348                            packed_type,
1349                            SideEffects::None(),
1350                            /* number_of_inputs= */ 2,
1351                            vector_length,
1352                            dex_pc) {
1353     DCHECK(!left->IsVecOperation());
1354     DCHECK(!left->IsVecPredSetOperation());
1355     DCHECK(!right->IsVecOperation());
1356     DCHECK(!right->IsVecPredSetOperation());
1357     DCHECK(DataType::IsIntegralType(left->GetType()));
1358     DCHECK(DataType::IsIntegralType(right->GetType()));
1359     SetRawInputAt(0, left);
1360     SetRawInputAt(1, right);
1361     SetPackedField<CondKindField>(cond);
1362   }
1363 
1364   // This is a special loop control instruction which must not be predicated.
MustBePredicatedInPredicatedSIMDMode()1365   bool MustBePredicatedInPredicatedSIMDMode() override { return false; }
1366 
GetCondKind()1367   CondKind GetCondKind() const {
1368     return GetPackedField<CondKindField>();
1369   }
1370 
1371   DECLARE_INSTRUCTION(VecPredWhile);
1372 
1373  protected:
1374   // Additional packed bits.
1375   static constexpr size_t kCondKind = HVecOperation::kNumberOfVectorOpPackedBits;
1376   static constexpr size_t kCondKindSize =
1377       MinimumBitsToStore(static_cast<size_t>(CondKind::kLast));
1378   static constexpr size_t kNumberOfVecPredConditionPackedBits = kCondKind + kCondKindSize;
1379   static_assert(kNumberOfVecPredConditionPackedBits <= kMaxNumberOfPackedBits,
1380                 "Too many packed fields.");
1381   using CondKindField = BitField<CondKind, kCondKind, kCondKindSize>;
1382 
1383   DEFAULT_COPY_CONSTRUCTOR(VecPredWhile);
1384 };
1385 
1386 // Evaluates the predicate condition (PCondKind) for a vector predicate; outputs
1387 // a scalar boolean value result.
1388 //
1389 // Note: as VecPredCondition can be also predicated, only active elements (determined by the
1390 // instruction's governing predicate) of the input vector predicate are used for condition
1391 // evaluation.
1392 //
1393 // Note: this instruction is currently used as a workaround for the fact that IR instructions
1394 // can't have more than one output.
1395 class HVecPredCondition final : public HVecOperation {
1396  public:
1397   // To get more info on the condition kinds please see "2.2 Process state, PSTATE" section of
1398   // "ARM Architecture Reference Manual Supplement. The Scalable Vector Extension (SVE),
1399   // for ARMv8-A".
1400   enum class PCondKind {
1401     kNone,    // No active elements were TRUE.
1402     kAny,     // An active element was TRUE.
1403     kNLast,   // The last active element was not TRUE.
1404     kLast,    // The last active element was TRUE.
1405     kFirst,   // The first active element was TRUE.
1406     kNFirst,  // The first active element was not TRUE.
1407     kPMore,   // An active element was TRUE but not the last active element.
1408     kPLast,   // The last active element was TRUE or no active elements were TRUE.
1409     kEnumLast = kPLast
1410   };
1411 
HVecPredCondition(ArenaAllocator * allocator,HInstruction * input,PCondKind pred_cond,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)1412   HVecPredCondition(ArenaAllocator* allocator,
1413                     HInstruction* input,
1414                     PCondKind pred_cond,
1415                     DataType::Type packed_type,
1416                     size_t vector_length,
1417                     uint32_t dex_pc)
1418       : HVecOperation(kVecPredCondition,
1419                       allocator,
1420                       packed_type,
1421                       SideEffects::None(),
1422                       /* number_of_inputs */ 1,
1423                       vector_length,
1424                       dex_pc) {
1425     DCHECK(input->IsVecPredSetOperation());
1426     SetRawInputAt(0, input);
1427     // Overrides the kSIMDType set by the VecOperation constructor.
1428     SetPackedField<TypeField>(DataType::Type::kBool);
1429     SetPackedField<CondKindField>(pred_cond);
1430   }
1431 
1432   // This instruction is currently used only as a special loop control instruction
1433   // which must not be predicated.
1434   // TODO: Remove the constraint.
MustBePredicatedInPredicatedSIMDMode()1435   bool MustBePredicatedInPredicatedSIMDMode() override { return false; }
1436 
GetPCondKind()1437   PCondKind GetPCondKind() const {
1438     return GetPackedField<CondKindField>();
1439   }
1440 
1441   DECLARE_INSTRUCTION(VecPredCondition);
1442 
1443  protected:
1444   // Additional packed bits.
1445   static constexpr size_t kCondKind = HVecOperation::kNumberOfVectorOpPackedBits;
1446   static constexpr size_t kCondKindSize =
1447       MinimumBitsToStore(static_cast<size_t>(PCondKind::kEnumLast));
1448   static constexpr size_t kNumberOfVecPredConditionPackedBits = kCondKind + kCondKindSize;
1449   static_assert(kNumberOfVecPredConditionPackedBits <= kMaxNumberOfPackedBits,
1450                 "Too many packed fields.");
1451   using CondKindField = BitField<PCondKind, kCondKind, kCondKindSize>;
1452 
1453   DEFAULT_COPY_CONSTRUCTOR(VecPredCondition);
1454 };
1455 
1456 }  // namespace art
1457 
1458 #endif  // ART_COMPILER_OPTIMIZING_NODES_VECTOR_H_
1459