blob: 9f9b918f173b349f18c313312b38c9888dfc6b4e [file] [log] [blame]
Aart Bikf8f5a162017-02-06 15:35:29 -08001/*
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
24namespace 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.
30class Alignment {
31 public:
32 Alignment(size_t base, size_t offset) : base_(base), offset_(offset) {
33 DCHECK_LT(offset, base);
34 DCHECK(IsPowerOfTwo(base));
35 }
36
37 // Returns true if memory is "at least" aligned at the given boundary.
38 // Assumes requested base is power of two.
39 bool IsAlignedAt(size_t base) const {
40 DCHECK_NE(0u, base);
41 DCHECK(IsPowerOfTwo(base));
42 return ((offset_ | base_) & (base - 1u)) == 0;
43 }
44
45 std::string ToString() const {
46 return "ALIGN(" + std::to_string(base_) + "," + std::to_string(offset_) + ")";
47 }
48
49 private:
50 size_t base_;
51 size_t offset_;
52};
53
54//
55// Definitions of abstract vector operations in HIR.
56//
57
58// Abstraction of a vector operation, i.e., an operation that performs
59// GetVectorLength() x GetPackedType() operations simultaneously.
60class HVecOperation : public HVariableInputSizeInstruction {
61 public:
62 HVecOperation(ArenaAllocator* arena,
63 Primitive::Type packed_type,
64 SideEffects side_effects,
65 size_t number_of_inputs,
66 size_t vector_length,
67 uint32_t dex_pc)
68 : HVariableInputSizeInstruction(side_effects,
69 dex_pc,
70 arena,
71 number_of_inputs,
72 kArenaAllocVectorNode),
73 vector_length_(vector_length) {
74 SetPackedField<TypeField>(packed_type);
75 DCHECK_LT(1u, vector_length);
76 }
77
78 // Returns the number of elements packed in a vector.
79 size_t GetVectorLength() const {
80 return vector_length_;
81 }
82
83 // Returns the number of bytes in a full vector.
84 size_t GetVectorNumberOfBytes() const {
85 return vector_length_ * Primitive::ComponentSize(GetPackedType());
86 }
87
88 // Returns the type of the vector operation: a SIMD operation looks like a FPU location.
89 // TODO: we could introduce SIMD types in HIR.
90 Primitive::Type GetType() const OVERRIDE {
91 return Primitive::kPrimDouble;
92 }
93
94 // Returns the true component type packed in a vector.
95 Primitive::Type GetPackedType() const {
96 return GetPackedField<TypeField>();
97 }
98
99 DECLARE_ABSTRACT_INSTRUCTION(VecOperation);
100
101 private:
102 // Additional packed bits.
103 static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
104 static constexpr size_t kFieldTypeSize =
105 MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
106 static constexpr size_t kNumberOfVectorOpPackedBits = kFieldType + kFieldTypeSize;
107 static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
108 using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
109
110 const size_t vector_length_;
111
112 DISALLOW_COPY_AND_ASSIGN(HVecOperation);
113};
114
115// Abstraction of a unary vector operation.
116class HVecUnaryOperation : public HVecOperation {
117 public:
118 HVecUnaryOperation(ArenaAllocator* arena,
119 Primitive::Type packed_type,
120 size_t vector_length,
121 uint32_t dex_pc)
122 : HVecOperation(arena,
123 packed_type,
124 SideEffects::None(),
125 /*number_of_inputs*/ 1,
126 vector_length,
127 dex_pc) { }
128 DECLARE_ABSTRACT_INSTRUCTION(VecUnaryOperation);
129 private:
130 DISALLOW_COPY_AND_ASSIGN(HVecUnaryOperation);
131};
132
133// Abstraction of a binary vector operation.
134class HVecBinaryOperation : public HVecOperation {
135 public:
136 HVecBinaryOperation(ArenaAllocator* arena,
137 Primitive::Type packed_type,
138 size_t vector_length,
139 uint32_t dex_pc)
140 : HVecOperation(arena,
141 packed_type,
142 SideEffects::None(),
143 /*number_of_inputs*/ 2,
144 vector_length,
145 dex_pc) { }
146 DECLARE_ABSTRACT_INSTRUCTION(VecBinaryOperation);
147 private:
148 DISALLOW_COPY_AND_ASSIGN(HVecBinaryOperation);
149};
150
151// Abstraction of a vector operation that references memory, with an alignment.
152// The Android runtime guarantees at least "component size" alignment for array
153// elements and, thus, vectors.
154class HVecMemoryOperation : public HVecOperation {
155 public:
156 HVecMemoryOperation(ArenaAllocator* arena,
157 Primitive::Type packed_type,
158 SideEffects side_effects,
159 size_t number_of_inputs,
160 size_t vector_length,
161 uint32_t dex_pc)
162 : HVecOperation(arena, packed_type, side_effects, number_of_inputs, vector_length, dex_pc),
163 alignment_(Primitive::ComponentSize(packed_type), 0) { }
164
165 void SetAlignment(Alignment alignment) { alignment_ = alignment; }
166
167 Alignment GetAlignment() const { return alignment_; }
168
169 DECLARE_ABSTRACT_INSTRUCTION(VecMemoryOperation);
170
171 private:
172 Alignment alignment_;
173
174 DISALLOW_COPY_AND_ASSIGN(HVecMemoryOperation);
175};
176
177//
178// Definitions of concrete vector operations in HIR.
179//
180
181// Replicates the given scalar into a vector,
182// viz. replicate(x) = [ x, .. , x ].
183class HVecReplicateScalar FINAL : public HVecUnaryOperation {
184 public:
185 HVecReplicateScalar(ArenaAllocator* arena,
186 HInstruction* scalar,
187 Primitive::Type packed_type,
188 size_t vector_length,
189 uint32_t dex_pc = kNoDexPc)
190 : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) {
191 SetRawInputAt(0, scalar);
192 }
193 DECLARE_INSTRUCTION(VecReplicateScalar);
194 private:
195 DISALLOW_COPY_AND_ASSIGN(HVecReplicateScalar);
196};
197
198// Assigns the given scalar elements to a vector,
199// viz. set( array(x1, .., xn) ) = [ x1, .. , xn ].
200class HVecSetScalars FINAL : public HVecUnaryOperation {
201 HVecSetScalars(ArenaAllocator* arena,
202 HInstruction** scalars, // array
203 Primitive::Type packed_type,
204 size_t vector_length,
205 uint32_t dex_pc = kNoDexPc)
206 : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) {
207 for (size_t i = 0; i < vector_length; i++) {
208 SetRawInputAt(0, scalars[i]);
209 }
210 }
211 DECLARE_INSTRUCTION(VecSetScalars);
212 private:
213 DISALLOW_COPY_AND_ASSIGN(HVecSetScalars);
214};
215
216// Sum-reduces the given vector into a shorter vector (m < n) or scalar (m = 1),
217// viz. sum-reduce[ x1, .. , xn ] = [ y1, .., ym ], where yi = sum_j x_j.
218class HVecSumReduce FINAL : public HVecUnaryOperation {
219 HVecSumReduce(ArenaAllocator* arena,
220 HInstruction* input,
221 Primitive::Type packed_type,
222 size_t vector_length,
223 uint32_t dex_pc = kNoDexPc)
224 : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) {
225 DCHECK(input->IsVecOperation());
226 DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type);
227 SetRawInputAt(0, input);
228 }
229
230 // TODO: probably integral promotion
231 Primitive::Type GetType() const OVERRIDE { return GetPackedType(); }
232
233 DECLARE_INSTRUCTION(VecSumReduce);
234 private:
235 DISALLOW_COPY_AND_ASSIGN(HVecSumReduce);
236};
237
238// Converts every component in the vector,
239// viz. cnv[ x1, .. , xn ] = [ cnv(x1), .. , cnv(xn) ].
240class HVecCnv FINAL : public HVecUnaryOperation {
241 public:
242 HVecCnv(ArenaAllocator* arena,
243 HInstruction* input,
244 Primitive::Type packed_type,
245 size_t vector_length,
246 uint32_t dex_pc = kNoDexPc)
247 : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) {
248 DCHECK(input->IsVecOperation());
249 DCHECK_NE(input->AsVecOperation()->GetPackedType(), packed_type); // actual convert
250 SetRawInputAt(0, input);
251 }
252
253 Primitive::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); }
254 Primitive::Type GetResultType() const { return GetPackedType(); }
255
256 DECLARE_INSTRUCTION(VecCnv);
257
258 private:
259 DISALLOW_COPY_AND_ASSIGN(HVecCnv);
260};
261
262// Negates every component in the vector,
263// viz. neg[ x1, .. , xn ] = [ -x1, .. , -xn ].
264class HVecNeg FINAL : public HVecUnaryOperation {
265 public:
266 HVecNeg(ArenaAllocator* arena,
267 HInstruction* input,
268 Primitive::Type packed_type,
269 size_t vector_length,
270 uint32_t dex_pc = kNoDexPc)
271 : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) {
272 DCHECK(input->IsVecOperation());
273 DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type);
274 SetRawInputAt(0, input);
275 }
276 DECLARE_INSTRUCTION(VecNeg);
277 private:
278 DISALLOW_COPY_AND_ASSIGN(HVecNeg);
279};
280
281// Bitwise- or boolean-nots every component in the vector,
282// viz. not[ x1, .. , xn ] = [ ~x1, .. , ~xn ], or
283// not[ x1, .. , xn ] = [ !x1, .. , !xn ] for boolean.
284class HVecNot FINAL : public HVecUnaryOperation {
285 public:
286 HVecNot(ArenaAllocator* arena,
287 HInstruction* input,
288 Primitive::Type packed_type,
289 size_t vector_length,
290 uint32_t dex_pc = kNoDexPc)
291 : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) {
292 DCHECK(input->IsVecOperation());
293 SetRawInputAt(0, input);
294 }
295 DECLARE_INSTRUCTION(VecNot);
296 private:
297 DISALLOW_COPY_AND_ASSIGN(HVecNot);
298};
299
300// Adds every component in the two vectors,
301// viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 + y1, .. , xn + yn ].
302class HVecAdd FINAL : public HVecBinaryOperation {
303 public:
304 HVecAdd(ArenaAllocator* arena,
305 HInstruction* left,
306 HInstruction* right,
307 Primitive::Type packed_type,
308 size_t vector_length,
309 uint32_t dex_pc = kNoDexPc)
310 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
311 DCHECK(left->IsVecOperation() && right->IsVecOperation());
312 DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
313 DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
314 SetRawInputAt(0, left);
315 SetRawInputAt(1, right);
316 }
317 DECLARE_INSTRUCTION(VecAdd);
318 private:
319 DISALLOW_COPY_AND_ASSIGN(HVecAdd);
320};
321
322// Subtracts every component in the two vectors,
323// viz. [ x1, .. , xn ] - [ y1, .. , yn ] = [ x1 - y1, .. , xn - yn ].
324class HVecSub FINAL : public HVecBinaryOperation {
325 public:
326 HVecSub(ArenaAllocator* arena,
327 HInstruction* left,
328 HInstruction* right,
329 Primitive::Type packed_type,
330 size_t vector_length,
331 uint32_t dex_pc = kNoDexPc)
332 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
333 DCHECK(left->IsVecOperation() && right->IsVecOperation());
334 DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
335 DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
336 SetRawInputAt(0, left);
337 SetRawInputAt(1, right);
338 }
339 DECLARE_INSTRUCTION(VecSub);
340 private:
341 DISALLOW_COPY_AND_ASSIGN(HVecSub);
342};
343
344// Multiplies every component in the two vectors,
345// viz. [ x1, .. , xn ] * [ y1, .. , yn ] = [ x1 * y1, .. , xn * yn ].
346class HVecMul FINAL : public HVecBinaryOperation {
347 public:
348 HVecMul(ArenaAllocator* arena,
349 HInstruction* left,
350 HInstruction* right,
351 Primitive::Type packed_type,
352 size_t vector_length,
353 uint32_t dex_pc = kNoDexPc)
354 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
355 DCHECK(left->IsVecOperation() && right->IsVecOperation());
356 DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
357 DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
358 SetRawInputAt(0, left);
359 SetRawInputAt(1, right);
360 }
361 DECLARE_INSTRUCTION(VecMul);
362 private:
363 DISALLOW_COPY_AND_ASSIGN(HVecMul);
364};
365
366// Divides every component in the two vectors,
367// viz. [ x1, .. , xn ] / [ y1, .. , yn ] = [ x1 / y1, .. , xn / yn ].
368class HVecDiv FINAL : public HVecBinaryOperation {
369 public:
370 HVecDiv(ArenaAllocator* arena,
371 HInstruction* left,
372 HInstruction* right,
373 Primitive::Type packed_type,
374 size_t vector_length,
375 uint32_t dex_pc = kNoDexPc)
376 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
377 DCHECK(left->IsVecOperation() && right->IsVecOperation());
378 DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
379 DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
380 SetRawInputAt(0, left);
381 SetRawInputAt(1, right);
382 }
383 DECLARE_INSTRUCTION(VecDiv);
384 private:
385 DISALLOW_COPY_AND_ASSIGN(HVecDiv);
386};
387
388// Bitwise-ands every component in the two vectors,
389// viz. [ x1, .. , xn ] & [ y1, .. , yn ] = [ x1 & y1, .. , xn & yn ].
390class HVecAnd FINAL : public HVecBinaryOperation {
391 public:
392 HVecAnd(ArenaAllocator* arena,
393 HInstruction* left,
394 HInstruction* right,
395 Primitive::Type packed_type,
396 size_t vector_length,
397 uint32_t dex_pc = kNoDexPc)
398 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
399 DCHECK(left->IsVecOperation() && right->IsVecOperation());
400 SetRawInputAt(0, left);
401 SetRawInputAt(1, right);
402 }
403 DECLARE_INSTRUCTION(VecAnd);
404 private:
405 DISALLOW_COPY_AND_ASSIGN(HVecAnd);
406};
407
408// Bitwise-and-nots every component in the two vectors,
409// viz. [ x1, .. , xn ] and-not [ y1, .. , yn ] = [ ~x1 & y1, .. , ~xn & yn ].
410class HVecAndNot FINAL : public HVecBinaryOperation {
411 public:
412 HVecAndNot(ArenaAllocator* arena,
413 HInstruction* left,
414 HInstruction* right,
415 Primitive::Type packed_type,
416 size_t vector_length,
417 uint32_t dex_pc = kNoDexPc)
418 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
419 DCHECK(left->IsVecOperation() && right->IsVecOperation());
420 SetRawInputAt(0, left);
421 SetRawInputAt(1, right);
422 }
423 DECLARE_INSTRUCTION(VecAndNot);
424 private:
425 DISALLOW_COPY_AND_ASSIGN(HVecAndNot);
426};
427
428// Bitwise-ors every component in the two vectors,
429// viz. [ x1, .. , xn ] | [ y1, .. , yn ] = [ x1 | y1, .. , xn | yn ].
430class HVecOr FINAL : public HVecBinaryOperation {
431 public:
432 HVecOr(ArenaAllocator* arena,
433 HInstruction* left,
434 HInstruction* right,
435 Primitive::Type packed_type,
436 size_t vector_length,
437 uint32_t dex_pc = kNoDexPc)
438 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
439 DCHECK(left->IsVecOperation() && right->IsVecOperation());
440 SetRawInputAt(0, left);
441 SetRawInputAt(1, right);
442 }
443 DECLARE_INSTRUCTION(VecOr);
444 private:
445 DISALLOW_COPY_AND_ASSIGN(HVecOr);
446};
447
448// Bitwise-xors every component in the two vectors,
449// viz. [ x1, .. , xn ] ^ [ y1, .. , yn ] = [ x1 ^ y1, .. , xn ^ yn ].
450class HVecXor FINAL : public HVecBinaryOperation {
451 public:
452 HVecXor(ArenaAllocator* arena,
453 HInstruction* left,
454 HInstruction* right,
455 Primitive::Type packed_type,
456 size_t vector_length,
457 uint32_t dex_pc = kNoDexPc)
458 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
459 DCHECK(left->IsVecOperation() && right->IsVecOperation());
460 SetRawInputAt(0, left);
461 SetRawInputAt(1, right);
462 }
463 DECLARE_INSTRUCTION(VecXor);
464 private:
465 DISALLOW_COPY_AND_ASSIGN(HVecXor);
466};
467
468// Logically shifts every component in the vector left by the given distance,
469// viz. [ x1, .. , xn ] << d = [ x1 << d, .. , xn << d ].
470class HVecShl FINAL : public HVecBinaryOperation {
471 public:
472 HVecShl(ArenaAllocator* arena,
473 HInstruction* left,
474 HInstruction* right,
475 Primitive::Type packed_type,
476 size_t vector_length,
477 uint32_t dex_pc = kNoDexPc)
478 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
479 DCHECK(left->IsVecOperation());
480 DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
481 SetRawInputAt(0, left);
482 SetRawInputAt(1, right);
483 }
484 DECLARE_INSTRUCTION(VecShl);
485 private:
486 DISALLOW_COPY_AND_ASSIGN(HVecShl);
487};
488
489// Arithmetically shifts every component in the vector right by the given distance,
490// viz. [ x1, .. , xn ] >> d = [ x1 >> d, .. , xn >> d ].
491class HVecShr FINAL : public HVecBinaryOperation {
492 public:
493 HVecShr(ArenaAllocator* arena,
494 HInstruction* left,
495 HInstruction* right,
496 Primitive::Type packed_type,
497 size_t vector_length,
498 uint32_t dex_pc = kNoDexPc)
499 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
500 DCHECK(left->IsVecOperation());
501 DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
502 SetRawInputAt(0, left);
503 SetRawInputAt(1, right);
504 }
505 DECLARE_INSTRUCTION(VecShr);
506 private:
507 DISALLOW_COPY_AND_ASSIGN(HVecShr);
508};
509
510// Logically shifts every component in the vector right by the given distance,
511// viz. [ x1, .. , xn ] >>> d = [ x1 >>> d, .. , xn >>> d ].
512class HVecUShr FINAL : public HVecBinaryOperation {
513 public:
514 HVecUShr(ArenaAllocator* arena,
515 HInstruction* left,
516 HInstruction* right,
517 Primitive::Type packed_type,
518 size_t vector_length,
519 uint32_t dex_pc = kNoDexPc)
520 : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) {
521 DCHECK(left->IsVecOperation());
522 DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
523 SetRawInputAt(0, left);
524 SetRawInputAt(1, right);
525 }
526 DECLARE_INSTRUCTION(VecUShr);
527 private:
528 DISALLOW_COPY_AND_ASSIGN(HVecUShr);
529};
530
531// Loads a vector from memory, viz. load(mem, 1)
532// yield the vector [ mem(1), .. , mem(n) ].
533class HVecLoad FINAL : public HVecMemoryOperation {
534 public:
535 HVecLoad(ArenaAllocator* arena,
536 HInstruction* base,
537 HInstruction* index,
538 Primitive::Type packed_type,
539 size_t vector_length,
540 uint32_t dex_pc = kNoDexPc)
541 : HVecMemoryOperation(arena,
542 packed_type,
543 SideEffects::ArrayReadOfType(packed_type),
544 /*number_of_inputs*/ 2,
545 vector_length,
546 dex_pc) {
547 SetRawInputAt(0, base);
548 SetRawInputAt(1, index);
549 }
550 DECLARE_INSTRUCTION(VecLoad);
551 private:
552 DISALLOW_COPY_AND_ASSIGN(HVecLoad);
553};
554
555// Stores a vector to memory, viz. store(m, 1, [x1, .. , xn] )
556// sets mem(1) = x1, .. , mem(n) = xn.
557class HVecStore FINAL : public HVecMemoryOperation {
558 public:
559 HVecStore(ArenaAllocator* arena,
560 HInstruction* base,
561 HInstruction* index,
562 HInstruction* value,
563 Primitive::Type packed_type,
564 size_t vector_length,
565 uint32_t dex_pc = kNoDexPc)
566 : HVecMemoryOperation(arena,
567 packed_type,
568 SideEffects::ArrayWriteOfType(packed_type),
569 /*number_of_inputs*/ 3,
570 vector_length,
571 dex_pc) {
572 DCHECK(value->IsVecOperation());
573 DCHECK_EQ(value->AsVecOperation()->GetPackedType(), packed_type);
574 SetRawInputAt(0, base);
575 SetRawInputAt(1, index);
576 SetRawInputAt(2, value);
577 }
578 DECLARE_INSTRUCTION(VecStore);
579 private:
580 DISALLOW_COPY_AND_ASSIGN(HVecStore);
581};
582
583} // namespace art
584
585#endif // ART_COMPILER_OPTIMIZING_NODES_VECTOR_H_