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