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