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 DCHECK_LT(1u, vector_length);
91 }
92
93 // Returns the number of elements packed in a vector.
GetVectorLength()94 size_t GetVectorLength() const {
95 return vector_length_;
96 }
97
98 // Returns the number of bytes in a full vector.
GetVectorNumberOfBytes()99 size_t GetVectorNumberOfBytes() const {
100 return vector_length_ * DataType::Size(GetPackedType());
101 }
102
103 // Returns the true component type packed in a vector.
GetPackedType()104 DataType::Type GetPackedType() const {
105 return GetPackedField<PackedTypeField>();
106 }
107
108 // Assumes vector nodes cannot be moved by default. Each concrete implementation
109 // that can be moved should override this method and return true.
110 //
111 // Note: similar approach is used for instruction scheduling (if it is turned on for the target):
112 // by default HScheduler::IsSchedulable returns false for a particular HVecOperation.
113 // HScheduler${ARCH}::IsSchedulable can be overridden to return true for an instruction (see
114 // scheduler_arm64.h for example) if it is safe to schedule it; in this case one *must* also
115 // look at/update HScheduler${ARCH}::IsSchedulingBarrier for this instruction.
116 //
117 // Note: For newly introduced vector instructions HScheduler${ARCH}::IsSchedulingBarrier must be
118 // altered to return true if the instruction might reside outside the SIMD loop body since SIMD
119 // registers are not kept alive across vector loop boundaries (yet).
CanBeMoved()120 bool CanBeMoved() const override { return false; }
121
122 // Tests if all data of a vector node (vector length and packed type) is equal.
123 // Each concrete implementation that adds more fields should test equality of
124 // those fields in its own method *and* call all super methods.
InstructionDataEquals(const HInstruction * other)125 bool InstructionDataEquals(const HInstruction* other) const override {
126 DCHECK(other->IsVecOperation());
127 const HVecOperation* o = other->AsVecOperation();
128 return GetVectorLength() == o->GetVectorLength() && GetPackedType() == o->GetPackedType();
129 }
130
131 // Maps an integral type to the same-size signed type and leaves other types alone.
ToSignedType(DataType::Type type)132 static DataType::Type ToSignedType(DataType::Type type) {
133 switch (type) {
134 case DataType::Type::kBool: // 1-byte storage unit
135 case DataType::Type::kUint8:
136 return DataType::Type::kInt8;
137 case DataType::Type::kUint16:
138 return DataType::Type::kInt16;
139 default:
140 DCHECK(type != DataType::Type::kVoid && type != DataType::Type::kReference) << type;
141 return type;
142 }
143 }
144
145 // Maps an integral type to the same-size unsigned type and leaves other types alone.
ToUnsignedType(DataType::Type type)146 static DataType::Type ToUnsignedType(DataType::Type type) {
147 switch (type) {
148 case DataType::Type::kBool: // 1-byte storage unit
149 case DataType::Type::kInt8:
150 return DataType::Type::kUint8;
151 case DataType::Type::kInt16:
152 return DataType::Type::kUint16;
153 default:
154 DCHECK(type != DataType::Type::kVoid && type != DataType::Type::kReference) << type;
155 return type;
156 }
157 }
158
159 // Maps an integral type to the same-size (un)signed type. Leaves other types alone.
ToProperType(DataType::Type type,bool is_unsigned)160 static DataType::Type ToProperType(DataType::Type type, bool is_unsigned) {
161 return is_unsigned ? ToUnsignedType(type) : ToSignedType(type);
162 }
163
164 // Helper method to determine if an instruction returns a SIMD value.
165 // TODO: This method is needed until we introduce SIMD as proper type.
ReturnsSIMDValue(HInstruction * instruction)166 static bool ReturnsSIMDValue(HInstruction* instruction) {
167 if (instruction->IsVecOperation()) {
168 return !instruction->IsVecExtractScalar(); // only scalar returning vec op
169 } else if (instruction->IsPhi()) {
170 // Vectorizer only uses Phis in reductions, so checking for a 2-way phi
171 // with a direct vector operand as second argument suffices.
172 return
173 instruction->GetType() == kSIMDType &&
174 instruction->InputCount() == 2 &&
175 instruction->InputAt(1)->IsVecOperation();
176 }
177 return false;
178 }
179
180 DECLARE_ABSTRACT_INSTRUCTION(VecOperation);
181
182 protected:
183 // Additional packed bits.
184 static constexpr size_t kFieldPackedType = HInstruction::kNumberOfGenericPackedBits;
185 static constexpr size_t kFieldPackedTypeSize =
186 MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
187 static constexpr size_t kNumberOfVectorOpPackedBits = kFieldPackedType + kFieldPackedTypeSize;
188 static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
189 using PackedTypeField = BitField<DataType::Type, kFieldPackedType, kFieldPackedTypeSize>;
190
191 DEFAULT_COPY_CONSTRUCTOR(VecOperation);
192
193 private:
194 const size_t vector_length_;
195 };
196
197 // Abstraction of a unary vector operation.
198 class HVecUnaryOperation : public HVecOperation {
199 public:
HVecUnaryOperation(InstructionKind kind,ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)200 HVecUnaryOperation(InstructionKind kind,
201 ArenaAllocator* allocator,
202 HInstruction* input,
203 DataType::Type packed_type,
204 size_t vector_length,
205 uint32_t dex_pc)
206 : HVecOperation(kind,
207 allocator,
208 packed_type,
209 SideEffects::None(),
210 /* number_of_inputs= */ 1,
211 vector_length,
212 dex_pc) {
213 SetRawInputAt(0, input);
214 }
215
GetInput()216 HInstruction* GetInput() const { return InputAt(0); }
217
218 DECLARE_ABSTRACT_INSTRUCTION(VecUnaryOperation);
219
220 protected:
221 DEFAULT_COPY_CONSTRUCTOR(VecUnaryOperation);
222 };
223
224 // Abstraction of a binary vector operation.
225 class HVecBinaryOperation : public HVecOperation {
226 public:
HVecBinaryOperation(InstructionKind kind,ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)227 HVecBinaryOperation(InstructionKind kind,
228 ArenaAllocator* allocator,
229 HInstruction* left,
230 HInstruction* right,
231 DataType::Type packed_type,
232 size_t vector_length,
233 uint32_t dex_pc)
234 : HVecOperation(kind,
235 allocator,
236 packed_type,
237 SideEffects::None(),
238 /* number_of_inputs= */ 2,
239 vector_length,
240 dex_pc) {
241 SetRawInputAt(0, left);
242 SetRawInputAt(1, right);
243 }
244
GetLeft()245 HInstruction* GetLeft() const { return InputAt(0); }
GetRight()246 HInstruction* GetRight() const { return InputAt(1); }
247
248 DECLARE_ABSTRACT_INSTRUCTION(VecBinaryOperation);
249
250 protected:
251 DEFAULT_COPY_CONSTRUCTOR(VecBinaryOperation);
252 };
253
254 // Abstraction of a vector operation that references memory, with an alignment.
255 // The Android runtime guarantees elements have at least natural alignment.
256 class HVecMemoryOperation : public HVecOperation {
257 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)258 HVecMemoryOperation(InstructionKind kind,
259 ArenaAllocator* allocator,
260 DataType::Type packed_type,
261 SideEffects side_effects,
262 size_t number_of_inputs,
263 size_t vector_length,
264 uint32_t dex_pc)
265 : HVecOperation(kind,
266 allocator,
267 packed_type,
268 side_effects,
269 number_of_inputs,
270 vector_length,
271 dex_pc),
272 alignment_(DataType::Size(packed_type), 0) {
273 DCHECK_GE(number_of_inputs, 2u);
274 }
275
SetAlignment(Alignment alignment)276 void SetAlignment(Alignment alignment) { alignment_ = alignment; }
277
GetAlignment()278 Alignment GetAlignment() const { return alignment_; }
279
GetArray()280 HInstruction* GetArray() const { return InputAt(0); }
GetIndex()281 HInstruction* GetIndex() const { return InputAt(1); }
282
InstructionDataEquals(const HInstruction * other)283 bool InstructionDataEquals(const HInstruction* other) const override {
284 DCHECK(other->IsVecMemoryOperation());
285 const HVecMemoryOperation* o = other->AsVecMemoryOperation();
286 return HVecOperation::InstructionDataEquals(o) && GetAlignment() == o->GetAlignment();
287 }
288
289 DECLARE_ABSTRACT_INSTRUCTION(VecMemoryOperation);
290
291 protected:
292 DEFAULT_COPY_CONSTRUCTOR(VecMemoryOperation);
293
294 private:
295 Alignment alignment_;
296 };
297
298 // Packed type consistency checker ("same vector length" integral types may mix freely).
299 // Tests relaxed type consistency in which packed same-size integral types can co-exist,
300 // but other type mixes are an error.
HasConsistentPackedTypes(HInstruction * input,DataType::Type type)301 inline static bool HasConsistentPackedTypes(HInstruction* input, DataType::Type type) {
302 if (input->IsPhi()) {
303 return input->GetType() == HVecOperation::kSIMDType; // carries SIMD
304 }
305 DCHECK(input->IsVecOperation());
306 DataType::Type input_type = input->AsVecOperation()->GetPackedType();
307 DCHECK_EQ(HVecOperation::ToUnsignedType(input_type) == HVecOperation::ToUnsignedType(type),
308 HVecOperation::ToSignedType(input_type) == HVecOperation::ToSignedType(type));
309 return HVecOperation::ToSignedType(input_type) == HVecOperation::ToSignedType(type);
310 }
311
312 //
313 // Definitions of concrete unary vector operations in HIR.
314 //
315
316 // Replicates the given scalar into a vector,
317 // viz. replicate(x) = [ x, .. , x ].
318 class HVecReplicateScalar final : public HVecUnaryOperation {
319 public:
HVecReplicateScalar(ArenaAllocator * allocator,HInstruction * scalar,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)320 HVecReplicateScalar(ArenaAllocator* allocator,
321 HInstruction* scalar,
322 DataType::Type packed_type,
323 size_t vector_length,
324 uint32_t dex_pc)
325 : HVecUnaryOperation(
326 kVecReplicateScalar, allocator, scalar, packed_type, vector_length, dex_pc) {
327 DCHECK(!ReturnsSIMDValue(scalar));
328 }
329
330 // A replicate needs to stay in place, since SIMD registers are not
331 // kept alive across vector loop boundaries (yet).
CanBeMoved()332 bool CanBeMoved() const override { return false; }
333
334 DECLARE_INSTRUCTION(VecReplicateScalar);
335
336 protected:
337 DEFAULT_COPY_CONSTRUCTOR(VecReplicateScalar);
338 };
339
340 // Extracts a particular scalar from the given vector,
341 // viz. extract[ x1, .. , xn ] = x_i.
342 //
343 // TODO: for now only i == 1 case supported.
344 class HVecExtractScalar final : public HVecUnaryOperation {
345 public:
HVecExtractScalar(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,size_t index,uint32_t dex_pc)346 HVecExtractScalar(ArenaAllocator* allocator,
347 HInstruction* input,
348 DataType::Type packed_type,
349 size_t vector_length,
350 size_t index,
351 uint32_t dex_pc)
352 : HVecUnaryOperation(
353 kVecExtractScalar, allocator, input, packed_type, vector_length, dex_pc) {
354 DCHECK(HasConsistentPackedTypes(input, packed_type));
355 DCHECK_LT(index, vector_length);
356 DCHECK_EQ(index, 0u);
357 // Yields a single component in the vector.
358 // Overrides the kSIMDType set by the VecOperation constructor.
359 SetPackedField<TypeField>(packed_type);
360 }
361
362 // An extract needs to stay in place, since SIMD registers are not
363 // kept alive across vector loop boundaries (yet).
CanBeMoved()364 bool CanBeMoved() const override { return false; }
365
366 DECLARE_INSTRUCTION(VecExtractScalar);
367
368 protected:
369 DEFAULT_COPY_CONSTRUCTOR(VecExtractScalar);
370 };
371
372 // Reduces the given vector into the first element as sum/min/max,
373 // viz. sum-reduce[ x1, .. , xn ] = [ y, ---- ], where y = sum xi
374 // and the "-" denotes "don't care" (implementation dependent).
375 class HVecReduce final : public HVecUnaryOperation {
376 public:
377 enum ReductionKind {
378 kSum = 1,
379 kMin = 2,
380 kMax = 3
381 };
382
HVecReduce(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,ReductionKind reduction_kind,uint32_t dex_pc)383 HVecReduce(ArenaAllocator* allocator,
384 HInstruction* input,
385 DataType::Type packed_type,
386 size_t vector_length,
387 ReductionKind reduction_kind,
388 uint32_t dex_pc)
389 : HVecUnaryOperation(kVecReduce, allocator, input, packed_type, vector_length, dex_pc),
390 reduction_kind_(reduction_kind) {
391 DCHECK(HasConsistentPackedTypes(input, packed_type));
392 }
393
GetReductionKind()394 ReductionKind GetReductionKind() const { return reduction_kind_; }
395
CanBeMoved()396 bool CanBeMoved() const override { return true; }
397
InstructionDataEquals(const HInstruction * other)398 bool InstructionDataEquals(const HInstruction* other) const override {
399 DCHECK(other->IsVecReduce());
400 const HVecReduce* o = other->AsVecReduce();
401 return HVecOperation::InstructionDataEquals(o) && GetReductionKind() == o->GetReductionKind();
402 }
403
404 DECLARE_INSTRUCTION(VecReduce);
405
406 protected:
407 DEFAULT_COPY_CONSTRUCTOR(VecReduce);
408
409 private:
410 const ReductionKind reduction_kind_;
411 };
412
413 // Converts every component in the vector,
414 // viz. cnv[ x1, .. , xn ] = [ cnv(x1), .. , cnv(xn) ].
415 class HVecCnv final : public HVecUnaryOperation {
416 public:
HVecCnv(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)417 HVecCnv(ArenaAllocator* allocator,
418 HInstruction* input,
419 DataType::Type packed_type,
420 size_t vector_length,
421 uint32_t dex_pc)
422 : HVecUnaryOperation(kVecCnv, allocator, input, packed_type, vector_length, dex_pc) {
423 DCHECK(input->IsVecOperation());
424 DCHECK_NE(GetInputType(), GetResultType()); // actual convert
425 }
426
GetInputType()427 DataType::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); }
GetResultType()428 DataType::Type GetResultType() const { return GetPackedType(); }
429
CanBeMoved()430 bool CanBeMoved() const override { return true; }
431
432 DECLARE_INSTRUCTION(VecCnv);
433
434 protected:
435 DEFAULT_COPY_CONSTRUCTOR(VecCnv);
436 };
437
438 // Negates every component in the vector,
439 // viz. neg[ x1, .. , xn ] = [ -x1, .. , -xn ].
440 class HVecNeg final : public HVecUnaryOperation {
441 public:
HVecNeg(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)442 HVecNeg(ArenaAllocator* allocator,
443 HInstruction* input,
444 DataType::Type packed_type,
445 size_t vector_length,
446 uint32_t dex_pc)
447 : HVecUnaryOperation(kVecNeg, allocator, input, packed_type, vector_length, dex_pc) {
448 DCHECK(HasConsistentPackedTypes(input, packed_type));
449 }
450
CanBeMoved()451 bool CanBeMoved() const override { return true; }
452
453 DECLARE_INSTRUCTION(VecNeg);
454
455 protected:
456 DEFAULT_COPY_CONSTRUCTOR(VecNeg);
457 };
458
459 // Takes absolute value of every component in the vector,
460 // viz. abs[ x1, .. , xn ] = [ |x1|, .. , |xn| ]
461 // for signed operand x.
462 class HVecAbs final : public HVecUnaryOperation {
463 public:
HVecAbs(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)464 HVecAbs(ArenaAllocator* allocator,
465 HInstruction* input,
466 DataType::Type packed_type,
467 size_t vector_length,
468 uint32_t dex_pc)
469 : HVecUnaryOperation(kVecAbs, allocator, input, packed_type, vector_length, dex_pc) {
470 DCHECK(HasConsistentPackedTypes(input, packed_type));
471 }
472
CanBeMoved()473 bool CanBeMoved() const override { return true; }
474
475 DECLARE_INSTRUCTION(VecAbs);
476
477 protected:
478 DEFAULT_COPY_CONSTRUCTOR(VecAbs);
479 };
480
481 // Bitwise- or boolean-nots every component in the vector,
482 // viz. not[ x1, .. , xn ] = [ ~x1, .. , ~xn ], or
483 // not[ x1, .. , xn ] = [ !x1, .. , !xn ] for boolean.
484 class HVecNot final : public HVecUnaryOperation {
485 public:
HVecNot(ArenaAllocator * allocator,HInstruction * input,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)486 HVecNot(ArenaAllocator* allocator,
487 HInstruction* input,
488 DataType::Type packed_type,
489 size_t vector_length,
490 uint32_t dex_pc)
491 : HVecUnaryOperation(kVecNot, allocator, input, packed_type, vector_length, dex_pc) {
492 DCHECK(input->IsVecOperation());
493 }
494
CanBeMoved()495 bool CanBeMoved() const override { return true; }
496
497 DECLARE_INSTRUCTION(VecNot);
498
499 protected:
500 DEFAULT_COPY_CONSTRUCTOR(VecNot);
501 };
502
503 //
504 // Definitions of concrete binary vector operations in HIR.
505 //
506
507 // Adds every component in the two vectors,
508 // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 + y1, .. , xn + yn ].
509 class HVecAdd final : public HVecBinaryOperation {
510 public:
HVecAdd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)511 HVecAdd(ArenaAllocator* allocator,
512 HInstruction* left,
513 HInstruction* right,
514 DataType::Type packed_type,
515 size_t vector_length,
516 uint32_t dex_pc)
517 : HVecBinaryOperation(kVecAdd, allocator, left, right, packed_type, vector_length, dex_pc) {
518 DCHECK(HasConsistentPackedTypes(left, packed_type));
519 DCHECK(HasConsistentPackedTypes(right, packed_type));
520 }
521
CanBeMoved()522 bool CanBeMoved() const override { return true; }
523
524 DECLARE_INSTRUCTION(VecAdd);
525
526 protected:
527 DEFAULT_COPY_CONSTRUCTOR(VecAdd);
528 };
529
530 // Adds every component in the two vectors using saturation arithmetic,
531 // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 +_sat y1, .. , xn +_sat yn ]
532 // for either both signed or both unsigned operands x, y (reflected in packed_type).
533 class HVecSaturationAdd final : public HVecBinaryOperation {
534 public:
HVecSaturationAdd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)535 HVecSaturationAdd(ArenaAllocator* allocator,
536 HInstruction* left,
537 HInstruction* right,
538 DataType::Type packed_type,
539 size_t vector_length,
540 uint32_t dex_pc)
541 : HVecBinaryOperation(
542 kVecSaturationAdd, allocator, left, right, packed_type, vector_length, dex_pc) {
543 DCHECK(HasConsistentPackedTypes(left, packed_type));
544 DCHECK(HasConsistentPackedTypes(right, packed_type));
545 }
546
CanBeMoved()547 bool CanBeMoved() const override { return true; }
548
549 DECLARE_INSTRUCTION(VecSaturationAdd);
550
551 protected:
552 DEFAULT_COPY_CONSTRUCTOR(VecSaturationAdd);
553 };
554
555 // Performs halving add on every component in the two vectors, viz.
556 // rounded [ x1, .. , xn ] hradd [ y1, .. , yn ] = [ (x1 + y1 + 1) >> 1, .. , (xn + yn + 1) >> 1 ]
557 // truncated [ x1, .. , xn ] hadd [ y1, .. , yn ] = [ (x1 + y1) >> 1, .. , (xn + yn ) >> 1 ]
558 // for either both signed or both unsigned operands x, y (reflected in packed_type).
559 class HVecHalvingAdd final : public HVecBinaryOperation {
560 public:
HVecHalvingAdd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,bool is_rounded,uint32_t dex_pc)561 HVecHalvingAdd(ArenaAllocator* allocator,
562 HInstruction* left,
563 HInstruction* right,
564 DataType::Type packed_type,
565 size_t vector_length,
566 bool is_rounded,
567 uint32_t dex_pc)
568 : HVecBinaryOperation(
569 kVecHalvingAdd, allocator, left, right, packed_type, vector_length, dex_pc) {
570 DCHECK(HasConsistentPackedTypes(left, packed_type));
571 DCHECK(HasConsistentPackedTypes(right, packed_type));
572 SetPackedFlag<kFieldHAddIsRounded>(is_rounded);
573 }
574
IsRounded()575 bool IsRounded() const { return GetPackedFlag<kFieldHAddIsRounded>(); }
576
CanBeMoved()577 bool CanBeMoved() const override { return true; }
578
InstructionDataEquals(const HInstruction * other)579 bool InstructionDataEquals(const HInstruction* other) const override {
580 DCHECK(other->IsVecHalvingAdd());
581 const HVecHalvingAdd* o = other->AsVecHalvingAdd();
582 return HVecOperation::InstructionDataEquals(o) && IsRounded() == o->IsRounded();
583 }
584
585 DECLARE_INSTRUCTION(VecHalvingAdd);
586
587 protected:
588 DEFAULT_COPY_CONSTRUCTOR(VecHalvingAdd);
589
590 private:
591 // Additional packed bits.
592 static constexpr size_t kFieldHAddIsRounded = HVecOperation::kNumberOfVectorOpPackedBits;
593 static constexpr size_t kNumberOfHAddPackedBits = kFieldHAddIsRounded + 1;
594 static_assert(kNumberOfHAddPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
595 };
596
597 // Subtracts every component in the two vectors,
598 // viz. [ x1, .. , xn ] - [ y1, .. , yn ] = [ x1 - y1, .. , xn - yn ].
599 class HVecSub final : public HVecBinaryOperation {
600 public:
HVecSub(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)601 HVecSub(ArenaAllocator* allocator,
602 HInstruction* left,
603 HInstruction* right,
604 DataType::Type packed_type,
605 size_t vector_length,
606 uint32_t dex_pc)
607 : HVecBinaryOperation(kVecSub, allocator, left, right, packed_type, vector_length, dex_pc) {
608 DCHECK(HasConsistentPackedTypes(left, packed_type));
609 DCHECK(HasConsistentPackedTypes(right, packed_type));
610 }
611
CanBeMoved()612 bool CanBeMoved() const override { return true; }
613
614 DECLARE_INSTRUCTION(VecSub);
615
616 protected:
617 DEFAULT_COPY_CONSTRUCTOR(VecSub);
618 };
619
620 // Subtracts every component in the two vectors using saturation arithmetic,
621 // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 -_sat y1, .. , xn -_sat yn ]
622 // for either both signed or both unsigned operands x, y (reflected in packed_type).
623 class HVecSaturationSub final : public HVecBinaryOperation {
624 public:
HVecSaturationSub(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)625 HVecSaturationSub(ArenaAllocator* allocator,
626 HInstruction* left,
627 HInstruction* right,
628 DataType::Type packed_type,
629 size_t vector_length,
630 uint32_t dex_pc)
631 : HVecBinaryOperation(
632 kVecSaturationSub, allocator, left, right, packed_type, vector_length, dex_pc) {
633 DCHECK(HasConsistentPackedTypes(left, packed_type));
634 DCHECK(HasConsistentPackedTypes(right, packed_type));
635 }
636
CanBeMoved()637 bool CanBeMoved() const override { return true; }
638
639 DECLARE_INSTRUCTION(VecSaturationSub);
640
641 protected:
642 DEFAULT_COPY_CONSTRUCTOR(VecSaturationSub);
643 };
644
645 // Multiplies every component in the two vectors,
646 // viz. [ x1, .. , xn ] * [ y1, .. , yn ] = [ x1 * y1, .. , xn * yn ].
647 class HVecMul final : public HVecBinaryOperation {
648 public:
HVecMul(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)649 HVecMul(ArenaAllocator* allocator,
650 HInstruction* left,
651 HInstruction* right,
652 DataType::Type packed_type,
653 size_t vector_length,
654 uint32_t dex_pc)
655 : HVecBinaryOperation(kVecMul, allocator, left, right, packed_type, vector_length, dex_pc) {
656 DCHECK(HasConsistentPackedTypes(left, packed_type));
657 DCHECK(HasConsistentPackedTypes(right, packed_type));
658 }
659
CanBeMoved()660 bool CanBeMoved() const override { return true; }
661
662 DECLARE_INSTRUCTION(VecMul);
663
664 protected:
665 DEFAULT_COPY_CONSTRUCTOR(VecMul);
666 };
667
668 // Divides every component in the two vectors,
669 // viz. [ x1, .. , xn ] / [ y1, .. , yn ] = [ x1 / y1, .. , xn / yn ].
670 class HVecDiv final : public HVecBinaryOperation {
671 public:
HVecDiv(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)672 HVecDiv(ArenaAllocator* allocator,
673 HInstruction* left,
674 HInstruction* right,
675 DataType::Type packed_type,
676 size_t vector_length,
677 uint32_t dex_pc)
678 : HVecBinaryOperation(kVecDiv, allocator, left, right, packed_type, vector_length, dex_pc) {
679 DCHECK(HasConsistentPackedTypes(left, packed_type));
680 DCHECK(HasConsistentPackedTypes(right, packed_type));
681 }
682
CanBeMoved()683 bool CanBeMoved() const override { return true; }
684
685 DECLARE_INSTRUCTION(VecDiv);
686
687 protected:
688 DEFAULT_COPY_CONSTRUCTOR(VecDiv);
689 };
690
691 // Takes minimum of every component in the two vectors,
692 // viz. MIN( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ min(x1, y1), .. , min(xn, yn) ]
693 // for either both signed or both unsigned operands x, y (reflected in packed_type).
694 class HVecMin final : public HVecBinaryOperation {
695 public:
HVecMin(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)696 HVecMin(ArenaAllocator* allocator,
697 HInstruction* left,
698 HInstruction* right,
699 DataType::Type packed_type,
700 size_t vector_length,
701 uint32_t dex_pc)
702 : HVecBinaryOperation(kVecMin, allocator, left, right, packed_type, vector_length, dex_pc) {
703 DCHECK(HasConsistentPackedTypes(left, packed_type));
704 DCHECK(HasConsistentPackedTypes(right, packed_type));
705 }
706
CanBeMoved()707 bool CanBeMoved() const override { return true; }
708
709 DECLARE_INSTRUCTION(VecMin);
710
711 protected:
712 DEFAULT_COPY_CONSTRUCTOR(VecMin);
713 };
714
715 // Takes maximum of every component in the two vectors,
716 // viz. MAX( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ max(x1, y1), .. , max(xn, yn) ]
717 // for either both signed or both unsigned operands x, y (reflected in packed_type).
718 class HVecMax final : public HVecBinaryOperation {
719 public:
HVecMax(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)720 HVecMax(ArenaAllocator* allocator,
721 HInstruction* left,
722 HInstruction* right,
723 DataType::Type packed_type,
724 size_t vector_length,
725 uint32_t dex_pc)
726 : HVecBinaryOperation(kVecMax, allocator, left, right, packed_type, vector_length, dex_pc) {
727 DCHECK(HasConsistentPackedTypes(left, packed_type));
728 DCHECK(HasConsistentPackedTypes(right, packed_type));
729 }
730
CanBeMoved()731 bool CanBeMoved() const override { return true; }
732
733 DECLARE_INSTRUCTION(VecMax);
734
735 protected:
736 DEFAULT_COPY_CONSTRUCTOR(VecMax);
737 };
738
739 // Bitwise-ands every component in the two vectors,
740 // viz. [ x1, .. , xn ] & [ y1, .. , yn ] = [ x1 & y1, .. , xn & yn ].
741 class HVecAnd final : public HVecBinaryOperation {
742 public:
HVecAnd(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)743 HVecAnd(ArenaAllocator* allocator,
744 HInstruction* left,
745 HInstruction* right,
746 DataType::Type packed_type,
747 size_t vector_length,
748 uint32_t dex_pc)
749 : HVecBinaryOperation(kVecAnd, allocator, left, right, packed_type, vector_length, dex_pc) {
750 DCHECK(left->IsVecOperation() && right->IsVecOperation());
751 }
752
CanBeMoved()753 bool CanBeMoved() const override { return true; }
754
755 DECLARE_INSTRUCTION(VecAnd);
756
757 protected:
758 DEFAULT_COPY_CONSTRUCTOR(VecAnd);
759 };
760
761 // Bitwise-and-nots every component in the two vectors,
762 // viz. [ x1, .. , xn ] and-not [ y1, .. , yn ] = [ ~x1 & y1, .. , ~xn & yn ].
763 class HVecAndNot final : public HVecBinaryOperation {
764 public:
HVecAndNot(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)765 HVecAndNot(ArenaAllocator* allocator,
766 HInstruction* left,
767 HInstruction* right,
768 DataType::Type packed_type,
769 size_t vector_length,
770 uint32_t dex_pc)
771 : HVecBinaryOperation(
772 kVecAndNot, allocator, left, right, packed_type, vector_length, dex_pc) {
773 DCHECK(left->IsVecOperation() && right->IsVecOperation());
774 }
775
CanBeMoved()776 bool CanBeMoved() const override { return true; }
777
778 DECLARE_INSTRUCTION(VecAndNot);
779
780 protected:
781 DEFAULT_COPY_CONSTRUCTOR(VecAndNot);
782 };
783
784 // Bitwise-ors every component in the two vectors,
785 // viz. [ x1, .. , xn ] | [ y1, .. , yn ] = [ x1 | y1, .. , xn | yn ].
786 class HVecOr final : public HVecBinaryOperation {
787 public:
HVecOr(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)788 HVecOr(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(kVecOr, allocator, left, right, packed_type, vector_length, dex_pc) {
795 DCHECK(left->IsVecOperation() && right->IsVecOperation());
796 }
797
CanBeMoved()798 bool CanBeMoved() const override { return true; }
799
800 DECLARE_INSTRUCTION(VecOr);
801
802 protected:
803 DEFAULT_COPY_CONSTRUCTOR(VecOr);
804 };
805
806 // Bitwise-xors every component in the two vectors,
807 // viz. [ x1, .. , xn ] ^ [ y1, .. , yn ] = [ x1 ^ y1, .. , xn ^ yn ].
808 class HVecXor final : public HVecBinaryOperation {
809 public:
HVecXor(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)810 HVecXor(ArenaAllocator* allocator,
811 HInstruction* left,
812 HInstruction* right,
813 DataType::Type packed_type,
814 size_t vector_length,
815 uint32_t dex_pc)
816 : HVecBinaryOperation(kVecXor, allocator, left, right, packed_type, vector_length, dex_pc) {
817 DCHECK(left->IsVecOperation() && right->IsVecOperation());
818 }
819
CanBeMoved()820 bool CanBeMoved() const override { return true; }
821
822 DECLARE_INSTRUCTION(VecXor);
823
824 protected:
825 DEFAULT_COPY_CONSTRUCTOR(VecXor);
826 };
827
828 // Logically shifts every component in the vector left by the given distance,
829 // viz. [ x1, .. , xn ] << d = [ x1 << d, .. , xn << d ].
830 class HVecShl final : public HVecBinaryOperation {
831 public:
HVecShl(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)832 HVecShl(ArenaAllocator* allocator,
833 HInstruction* left,
834 HInstruction* right,
835 DataType::Type packed_type,
836 size_t vector_length,
837 uint32_t dex_pc)
838 : HVecBinaryOperation(kVecShl, allocator, left, right, packed_type, vector_length, dex_pc) {
839 DCHECK(HasConsistentPackedTypes(left, packed_type));
840 }
841
CanBeMoved()842 bool CanBeMoved() const override { return true; }
843
844 DECLARE_INSTRUCTION(VecShl);
845
846 protected:
847 DEFAULT_COPY_CONSTRUCTOR(VecShl);
848 };
849
850 // Arithmetically shifts every component in the vector right by the given distance,
851 // viz. [ x1, .. , xn ] >> d = [ x1 >> d, .. , xn >> d ].
852 class HVecShr final : public HVecBinaryOperation {
853 public:
HVecShr(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)854 HVecShr(ArenaAllocator* allocator,
855 HInstruction* left,
856 HInstruction* right,
857 DataType::Type packed_type,
858 size_t vector_length,
859 uint32_t dex_pc)
860 : HVecBinaryOperation(kVecShr, allocator, left, right, packed_type, vector_length, dex_pc) {
861 DCHECK(HasConsistentPackedTypes(left, packed_type));
862 }
863
CanBeMoved()864 bool CanBeMoved() const override { return true; }
865
866 DECLARE_INSTRUCTION(VecShr);
867
868 protected:
869 DEFAULT_COPY_CONSTRUCTOR(VecShr);
870 };
871
872 // Logically shifts every component in the vector right by the given distance,
873 // viz. [ x1, .. , xn ] >>> d = [ x1 >>> d, .. , xn >>> d ].
874 class HVecUShr final : public HVecBinaryOperation {
875 public:
HVecUShr(ArenaAllocator * allocator,HInstruction * left,HInstruction * right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)876 HVecUShr(ArenaAllocator* allocator,
877 HInstruction* left,
878 HInstruction* right,
879 DataType::Type packed_type,
880 size_t vector_length,
881 uint32_t dex_pc)
882 : HVecBinaryOperation(kVecUShr, allocator, left, right, packed_type, vector_length, dex_pc) {
883 DCHECK(HasConsistentPackedTypes(left, packed_type));
884 }
885
CanBeMoved()886 bool CanBeMoved() const override { return true; }
887
888 DECLARE_INSTRUCTION(VecUShr);
889
890 protected:
891 DEFAULT_COPY_CONSTRUCTOR(VecUShr);
892 };
893
894 //
895 // Definitions of concrete miscellaneous vector operations in HIR.
896 //
897
898 // Assigns the given scalar elements to a vector,
899 // viz. set( array(x1, .. , xn) ) = [ x1, .. , xn ] if n == m,
900 // set( array(x1, .. , xm) ) = [ x1, .. , xm, 0, .. , 0 ] if m < n.
901 class HVecSetScalars final : public HVecOperation {
902 public:
HVecSetScalars(ArenaAllocator * allocator,HInstruction * scalars[],DataType::Type packed_type,size_t vector_length,size_t number_of_scalars,uint32_t dex_pc)903 HVecSetScalars(ArenaAllocator* allocator,
904 HInstruction* scalars[],
905 DataType::Type packed_type,
906 size_t vector_length,
907 size_t number_of_scalars,
908 uint32_t dex_pc)
909 : HVecOperation(kVecSetScalars,
910 allocator,
911 packed_type,
912 SideEffects::None(),
913 number_of_scalars,
914 vector_length,
915 dex_pc) {
916 for (size_t i = 0; i < number_of_scalars; i++) {
917 DCHECK(!ReturnsSIMDValue(scalars[i]));
918 SetRawInputAt(0, scalars[i]);
919 }
920 }
921
922 // Setting scalars needs to stay in place, since SIMD registers are not
923 // kept alive across vector loop boundaries (yet).
CanBeMoved()924 bool CanBeMoved() const override { return false; }
925
926 DECLARE_INSTRUCTION(VecSetScalars);
927
928 protected:
929 DEFAULT_COPY_CONSTRUCTOR(VecSetScalars);
930 };
931
932 // Multiplies every component in the two vectors, adds the result vector to the accumulator vector,
933 // viz. [ a1, .. , an ] + [ x1, .. , xn ] * [ y1, .. , yn ] = [ a1 + x1 * y1, .. , an + xn * yn ].
934 // For floating point types, Java rounding behavior must be preserved; the products are rounded to
935 // the proper precision before being added. "Fused" multiply-add operations available on several
936 // architectures are not usable since they would violate Java language rules.
937 class HVecMultiplyAccumulate final : public HVecOperation {
938 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)939 HVecMultiplyAccumulate(ArenaAllocator* allocator,
940 InstructionKind op,
941 HInstruction* accumulator,
942 HInstruction* mul_left,
943 HInstruction* mul_right,
944 DataType::Type packed_type,
945 size_t vector_length,
946 uint32_t dex_pc)
947 : HVecOperation(kVecMultiplyAccumulate,
948 allocator,
949 packed_type,
950 SideEffects::None(),
951 /* number_of_inputs= */ 3,
952 vector_length,
953 dex_pc),
954 op_kind_(op) {
955 DCHECK(op == InstructionKind::kAdd || op == InstructionKind::kSub);
956 DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
957 DCHECK(HasConsistentPackedTypes(mul_left, packed_type));
958 DCHECK(HasConsistentPackedTypes(mul_right, packed_type));
959 // Remove the following if we add an architecture that supports floating point multiply-add
960 // with Java-compatible rounding.
961 DCHECK(DataType::IsIntegralType(packed_type));
962 SetRawInputAt(0, accumulator);
963 SetRawInputAt(1, mul_left);
964 SetRawInputAt(2, mul_right);
965 }
966
CanBeMoved()967 bool CanBeMoved() const override { return true; }
968
InstructionDataEquals(const HInstruction * other)969 bool InstructionDataEquals(const HInstruction* other) const override {
970 DCHECK(other->IsVecMultiplyAccumulate());
971 const HVecMultiplyAccumulate* o = other->AsVecMultiplyAccumulate();
972 return HVecOperation::InstructionDataEquals(o) && GetOpKind() == o->GetOpKind();
973 }
974
GetOpKind()975 InstructionKind GetOpKind() const { return op_kind_; }
976
977 DECLARE_INSTRUCTION(VecMultiplyAccumulate);
978
979 protected:
980 DEFAULT_COPY_CONSTRUCTOR(VecMultiplyAccumulate);
981
982 private:
983 // Indicates if this is a MADD or MSUB.
984 const InstructionKind op_kind_;
985 };
986
987 // Takes the absolute difference of two vectors, and adds the results to
988 // same-precision or wider-precision components in the accumulator,
989 // viz. SAD([ a1, .. , am ], [ x1, .. , xn ], [ y1, .. , yn ]) =
990 // [ a1 + sum abs(xi-yi), .. , am + sum abs(xj-yj) ],
991 // for m <= n, non-overlapping sums, and signed operands x, y.
992 class HVecSADAccumulate final : public HVecOperation {
993 public:
HVecSADAccumulate(ArenaAllocator * allocator,HInstruction * accumulator,HInstruction * sad_left,HInstruction * sad_right,DataType::Type packed_type,size_t vector_length,uint32_t dex_pc)994 HVecSADAccumulate(ArenaAllocator* allocator,
995 HInstruction* accumulator,
996 HInstruction* sad_left,
997 HInstruction* sad_right,
998 DataType::Type packed_type,
999 size_t vector_length,
1000 uint32_t dex_pc)
1001 : HVecOperation(kVecSADAccumulate,
1002 allocator,
1003 packed_type,
1004 SideEffects::None(),
1005 /* number_of_inputs= */ 3,
1006 vector_length,
1007 dex_pc) {
1008 DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
1009 DCHECK(sad_left->IsVecOperation());
1010 DCHECK(sad_right->IsVecOperation());
1011 DCHECK_EQ(ToSignedType(sad_left->AsVecOperation()->GetPackedType()),
1012 ToSignedType(sad_right->AsVecOperation()->GetPackedType()));
1013 SetRawInputAt(0, accumulator);
1014 SetRawInputAt(1, sad_left);
1015 SetRawInputAt(2, sad_right);
1016 }
1017
1018 DECLARE_INSTRUCTION(VecSADAccumulate);
1019
1020 protected:
1021 DEFAULT_COPY_CONSTRUCTOR(VecSADAccumulate);
1022 };
1023
1024 // Performs dot product of two vectors and adds the result to wider precision components in
1025 // the accumulator.
1026 //
1027 // viz. DOT_PRODUCT([ a1, .. , am], [ x1, .. , xn ], [ y1, .. , yn ]) =
1028 // [ a1 + sum(xi * yi), .. , am + sum(xj * yj) ],
1029 // for m <= n, non-overlapping sums,
1030 // for either both signed or both unsigned operands x, y.
1031 //
1032 // Notes:
1033 // - packed type reflects the type of sum reduction, not the type of the operands.
1034 // - IsZeroExtending() is used to determine the kind of signed/zero extension to be
1035 // performed for the operands.
1036 //
1037 // TODO: Support types other than kInt32 for packed type.
1038 class HVecDotProd final : public HVecOperation {
1039 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)1040 HVecDotProd(ArenaAllocator* allocator,
1041 HInstruction* accumulator,
1042 HInstruction* left,
1043 HInstruction* right,
1044 DataType::Type packed_type,
1045 bool is_zero_extending,
1046 size_t vector_length,
1047 uint32_t dex_pc)
1048 : HVecOperation(kVecDotProd,
1049 allocator,
1050 packed_type,
1051 SideEffects::None(),
1052 /* number_of_inputs= */ 3,
1053 vector_length,
1054 dex_pc) {
1055 DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
1056 DCHECK(DataType::IsIntegralType(packed_type));
1057 DCHECK(left->IsVecOperation());
1058 DCHECK(right->IsVecOperation());
1059 DCHECK_EQ(ToSignedType(left->AsVecOperation()->GetPackedType()),
1060 ToSignedType(right->AsVecOperation()->GetPackedType()));
1061 SetRawInputAt(0, accumulator);
1062 SetRawInputAt(1, left);
1063 SetRawInputAt(2, right);
1064 SetPackedFlag<kFieldHDotProdIsZeroExtending>(is_zero_extending);
1065 }
1066
IsZeroExtending()1067 bool IsZeroExtending() const { return GetPackedFlag<kFieldHDotProdIsZeroExtending>(); }
1068
CanBeMoved()1069 bool CanBeMoved() const override { return true; }
1070
1071 DECLARE_INSTRUCTION(VecDotProd);
1072
1073 protected:
1074 DEFAULT_COPY_CONSTRUCTOR(VecDotProd);
1075
1076 private:
1077 // Additional packed bits.
1078 static constexpr size_t kFieldHDotProdIsZeroExtending =
1079 HVecOperation::kNumberOfVectorOpPackedBits;
1080 static constexpr size_t kNumberOfHDotProdPackedBits = kFieldHDotProdIsZeroExtending + 1;
1081 static_assert(kNumberOfHDotProdPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
1082 };
1083
1084 // Loads a vector from memory, viz. load(mem, 1)
1085 // yield the vector [ mem(1), .. , mem(n) ].
1086 class HVecLoad final : public HVecMemoryOperation {
1087 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)1088 HVecLoad(ArenaAllocator* allocator,
1089 HInstruction* base,
1090 HInstruction* index,
1091 DataType::Type packed_type,
1092 SideEffects side_effects,
1093 size_t vector_length,
1094 bool is_string_char_at,
1095 uint32_t dex_pc)
1096 : HVecMemoryOperation(kVecLoad,
1097 allocator,
1098 packed_type,
1099 side_effects,
1100 /* number_of_inputs= */ 2,
1101 vector_length,
1102 dex_pc) {
1103 SetRawInputAt(0, base);
1104 SetRawInputAt(1, index);
1105 SetPackedFlag<kFieldIsStringCharAt>(is_string_char_at);
1106 }
1107
IsStringCharAt()1108 bool IsStringCharAt() const { return GetPackedFlag<kFieldIsStringCharAt>(); }
1109
CanBeMoved()1110 bool CanBeMoved() const override { return true; }
1111
InstructionDataEquals(const HInstruction * other)1112 bool InstructionDataEquals(const HInstruction* other) const override {
1113 DCHECK(other->IsVecLoad());
1114 const HVecLoad* o = other->AsVecLoad();
1115 return HVecMemoryOperation::InstructionDataEquals(o) && IsStringCharAt() == o->IsStringCharAt();
1116 }
1117
1118 DECLARE_INSTRUCTION(VecLoad);
1119
1120 protected:
1121 DEFAULT_COPY_CONSTRUCTOR(VecLoad);
1122
1123 private:
1124 // Additional packed bits.
1125 static constexpr size_t kFieldIsStringCharAt = HVecOperation::kNumberOfVectorOpPackedBits;
1126 static constexpr size_t kNumberOfVecLoadPackedBits = kFieldIsStringCharAt + 1;
1127 static_assert(kNumberOfVecLoadPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
1128 };
1129
1130 // Stores a vector to memory, viz. store(m, 1, [x1, .. , xn] )
1131 // sets mem(1) = x1, .. , mem(n) = xn.
1132 class HVecStore final : public HVecMemoryOperation {
1133 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)1134 HVecStore(ArenaAllocator* allocator,
1135 HInstruction* base,
1136 HInstruction* index,
1137 HInstruction* value,
1138 DataType::Type packed_type,
1139 SideEffects side_effects,
1140 size_t vector_length,
1141 uint32_t dex_pc)
1142 : HVecMemoryOperation(kVecStore,
1143 allocator,
1144 packed_type,
1145 side_effects,
1146 /* number_of_inputs= */ 3,
1147 vector_length,
1148 dex_pc) {
1149 DCHECK(HasConsistentPackedTypes(value, packed_type));
1150 SetRawInputAt(0, base);
1151 SetRawInputAt(1, index);
1152 SetRawInputAt(2, value);
1153 }
1154
1155 // A store needs to stay in place.
CanBeMoved()1156 bool CanBeMoved() const override { return false; }
1157
1158 DECLARE_INSTRUCTION(VecStore);
1159
1160 protected:
1161 DEFAULT_COPY_CONSTRUCTOR(VecStore)
1162 };
1163
1164 } // namespace art
1165
1166 #endif // ART_COMPILER_OPTIMIZING_NODES_VECTOR_H_
1167