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 #include "code_generator_arm_vixl.h" 18 #include "mirror/array-inl.h" 19 20 namespace vixl32 = vixl::aarch32; 21 using namespace vixl32; // NOLINT(build/namespaces) 22 23 namespace art { 24 namespace arm { 25 26 using helpers::DRegisterFrom; 27 using helpers::Int64ConstantFrom; 28 using helpers::InputDRegisterAt; 29 using helpers::InputRegisterAt; 30 using helpers::OutputDRegister; 31 using helpers::RegisterFrom; 32 33 #define __ GetVIXLAssembler()-> 34 35 void LocationsBuilderARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) { 36 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 37 switch (instruction->GetPackedType()) { 38 case Primitive::kPrimBoolean: 39 case Primitive::kPrimByte: 40 case Primitive::kPrimChar: 41 case Primitive::kPrimShort: 42 case Primitive::kPrimInt: 43 locations->SetInAt(0, Location::RequiresRegister()); 44 locations->SetOut(Location::RequiresFpuRegister()); 45 break; 46 default: 47 LOG(FATAL) << "Unsupported SIMD type"; 48 UNREACHABLE(); 49 } 50 } 51 52 void InstructionCodeGeneratorARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) { 53 LocationSummary* locations = instruction->GetLocations(); 54 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 55 switch (instruction->GetPackedType()) { 56 case Primitive::kPrimBoolean: 57 case Primitive::kPrimByte: 58 DCHECK_EQ(8u, instruction->GetVectorLength()); 59 __ Vdup(Untyped8, dst, InputRegisterAt(instruction, 0)); 60 break; 61 case Primitive::kPrimChar: 62 case Primitive::kPrimShort: 63 DCHECK_EQ(4u, instruction->GetVectorLength()); 64 __ Vdup(Untyped16, dst, InputRegisterAt(instruction, 0)); 65 break; 66 case Primitive::kPrimInt: 67 DCHECK_EQ(2u, instruction->GetVectorLength()); 68 __ Vdup(Untyped32, dst, InputRegisterAt(instruction, 0)); 69 break; 70 default: 71 LOG(FATAL) << "Unsupported SIMD type"; 72 UNREACHABLE(); 73 } 74 } 75 76 void LocationsBuilderARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) { 77 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 78 } 79 80 void InstructionCodeGeneratorARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) { 81 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 82 } 83 84 void LocationsBuilderARMVIXL::VisitVecSumReduce(HVecSumReduce* instruction) { 85 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 86 } 87 88 void InstructionCodeGeneratorARMVIXL::VisitVecSumReduce(HVecSumReduce* instruction) { 89 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 90 } 91 92 // Helper to set up locations for vector unary operations. 93 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) { 94 LocationSummary* locations = new (arena) LocationSummary(instruction); 95 switch (instruction->GetPackedType()) { 96 case Primitive::kPrimBoolean: 97 locations->SetInAt(0, Location::RequiresFpuRegister()); 98 locations->SetOut(Location::RequiresFpuRegister(), 99 instruction->IsVecNot() ? Location::kOutputOverlap 100 : Location::kNoOutputOverlap); 101 break; 102 case Primitive::kPrimByte: 103 case Primitive::kPrimChar: 104 case Primitive::kPrimShort: 105 case Primitive::kPrimInt: 106 locations->SetInAt(0, Location::RequiresFpuRegister()); 107 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 108 break; 109 default: 110 LOG(FATAL) << "Unsupported SIMD type"; 111 UNREACHABLE(); 112 } 113 } 114 115 void LocationsBuilderARMVIXL::VisitVecCnv(HVecCnv* instruction) { 116 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 117 } 118 119 void InstructionCodeGeneratorARMVIXL::VisitVecCnv(HVecCnv* instruction) { 120 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 121 } 122 123 void LocationsBuilderARMVIXL::VisitVecNeg(HVecNeg* instruction) { 124 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 125 } 126 127 void InstructionCodeGeneratorARMVIXL::VisitVecNeg(HVecNeg* instruction) { 128 LocationSummary* locations = instruction->GetLocations(); 129 vixl32::DRegister src = DRegisterFrom(locations->InAt(0)); 130 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 131 switch (instruction->GetPackedType()) { 132 case Primitive::kPrimByte: 133 DCHECK_EQ(8u, instruction->GetVectorLength()); 134 __ Vneg(DataTypeValue::S8, dst, src); 135 break; 136 case Primitive::kPrimChar: 137 case Primitive::kPrimShort: 138 DCHECK_EQ(4u, instruction->GetVectorLength()); 139 __ Vneg(DataTypeValue::S16, dst, src); 140 break; 141 case Primitive::kPrimInt: 142 DCHECK_EQ(2u, instruction->GetVectorLength()); 143 __ Vneg(DataTypeValue::S32, dst, src); 144 break; 145 default: 146 LOG(FATAL) << "Unsupported SIMD type"; 147 UNREACHABLE(); 148 } 149 } 150 151 void LocationsBuilderARMVIXL::VisitVecAbs(HVecAbs* instruction) { 152 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 153 } 154 155 void InstructionCodeGeneratorARMVIXL::VisitVecAbs(HVecAbs* instruction) { 156 LocationSummary* locations = instruction->GetLocations(); 157 vixl32::DRegister src = DRegisterFrom(locations->InAt(0)); 158 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 159 switch (instruction->GetPackedType()) { 160 case Primitive::kPrimByte: 161 DCHECK_EQ(8u, instruction->GetVectorLength()); 162 __ Vabs(DataTypeValue::S8, dst, src); 163 break; 164 case Primitive::kPrimChar: 165 case Primitive::kPrimShort: 166 DCHECK_EQ(4u, instruction->GetVectorLength()); 167 __ Vabs(DataTypeValue::S16, dst, src); 168 break; 169 case Primitive::kPrimInt: 170 DCHECK_EQ(2u, instruction->GetVectorLength()); 171 __ Vabs(DataTypeValue::S32, dst, src); 172 break; 173 default: 174 LOG(FATAL) << "Unsupported SIMD type"; 175 UNREACHABLE(); 176 } 177 } 178 179 void LocationsBuilderARMVIXL::VisitVecNot(HVecNot* instruction) { 180 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 181 } 182 183 void InstructionCodeGeneratorARMVIXL::VisitVecNot(HVecNot* instruction) { 184 LocationSummary* locations = instruction->GetLocations(); 185 vixl32::DRegister src = DRegisterFrom(locations->InAt(0)); 186 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 187 switch (instruction->GetPackedType()) { 188 case Primitive::kPrimBoolean: // special case boolean-not 189 DCHECK_EQ(8u, instruction->GetVectorLength()); 190 __ Vmov(I8, dst, 1); 191 __ Veor(dst, dst, src); 192 break; 193 case Primitive::kPrimByte: 194 case Primitive::kPrimChar: 195 case Primitive::kPrimShort: 196 case Primitive::kPrimInt: 197 __ Vmvn(I8, dst, src); // lanes do not matter 198 break; 199 default: 200 LOG(FATAL) << "Unsupported SIMD type"; 201 UNREACHABLE(); 202 } 203 } 204 205 // Helper to set up locations for vector binary operations. 206 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) { 207 LocationSummary* locations = new (arena) LocationSummary(instruction); 208 switch (instruction->GetPackedType()) { 209 case Primitive::kPrimBoolean: 210 case Primitive::kPrimByte: 211 case Primitive::kPrimChar: 212 case Primitive::kPrimShort: 213 case Primitive::kPrimInt: 214 locations->SetInAt(0, Location::RequiresFpuRegister()); 215 locations->SetInAt(1, Location::RequiresFpuRegister()); 216 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 217 break; 218 default: 219 LOG(FATAL) << "Unsupported SIMD type"; 220 UNREACHABLE(); 221 } 222 } 223 224 void LocationsBuilderARMVIXL::VisitVecAdd(HVecAdd* instruction) { 225 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 226 } 227 228 void InstructionCodeGeneratorARMVIXL::VisitVecAdd(HVecAdd* instruction) { 229 LocationSummary* locations = instruction->GetLocations(); 230 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 231 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 232 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 233 switch (instruction->GetPackedType()) { 234 case Primitive::kPrimByte: 235 DCHECK_EQ(8u, instruction->GetVectorLength()); 236 __ Vadd(I8, dst, lhs, rhs); 237 break; 238 case Primitive::kPrimChar: 239 case Primitive::kPrimShort: 240 DCHECK_EQ(4u, instruction->GetVectorLength()); 241 __ Vadd(I16, dst, lhs, rhs); 242 break; 243 case Primitive::kPrimInt: 244 DCHECK_EQ(2u, instruction->GetVectorLength()); 245 __ Vadd(I32, dst, lhs, rhs); 246 break; 247 default: 248 LOG(FATAL) << "Unsupported SIMD type"; 249 UNREACHABLE(); 250 } 251 } 252 253 void LocationsBuilderARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) { 254 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 255 } 256 257 void InstructionCodeGeneratorARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) { 258 LocationSummary* locations = instruction->GetLocations(); 259 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 260 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 261 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 262 switch (instruction->GetPackedType()) { 263 case Primitive::kPrimByte: 264 DCHECK_EQ(8u, instruction->GetVectorLength()); 265 if (instruction->IsUnsigned()) { 266 instruction->IsRounded() 267 ? __ Vrhadd(DataTypeValue::U8, dst, lhs, rhs) 268 : __ Vhadd(DataTypeValue::U8, dst, lhs, rhs); 269 } else { 270 instruction->IsRounded() 271 ? __ Vrhadd(DataTypeValue::S8, dst, lhs, rhs) 272 : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs); 273 } 274 break; 275 case Primitive::kPrimChar: 276 case Primitive::kPrimShort: 277 DCHECK_EQ(4u, instruction->GetVectorLength()); 278 if (instruction->IsUnsigned()) { 279 instruction->IsRounded() 280 ? __ Vrhadd(DataTypeValue::U16, dst, lhs, rhs) 281 : __ Vhadd(DataTypeValue::U16, dst, lhs, rhs); 282 } else { 283 instruction->IsRounded() 284 ? __ Vrhadd(DataTypeValue::S16, dst, lhs, rhs) 285 : __ Vhadd(DataTypeValue::S16, dst, lhs, rhs); 286 } 287 break; 288 default: 289 LOG(FATAL) << "Unsupported SIMD type"; 290 UNREACHABLE(); 291 } 292 } 293 294 void LocationsBuilderARMVIXL::VisitVecSub(HVecSub* instruction) { 295 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 296 } 297 298 void InstructionCodeGeneratorARMVIXL::VisitVecSub(HVecSub* instruction) { 299 LocationSummary* locations = instruction->GetLocations(); 300 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 301 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 302 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 303 switch (instruction->GetPackedType()) { 304 case Primitive::kPrimByte: 305 DCHECK_EQ(8u, instruction->GetVectorLength()); 306 __ Vsub(I8, dst, lhs, rhs); 307 break; 308 case Primitive::kPrimChar: 309 case Primitive::kPrimShort: 310 DCHECK_EQ(4u, instruction->GetVectorLength()); 311 __ Vsub(I16, dst, lhs, rhs); 312 break; 313 case Primitive::kPrimInt: 314 DCHECK_EQ(2u, instruction->GetVectorLength()); 315 __ Vsub(I32, dst, lhs, rhs); 316 break; 317 default: 318 LOG(FATAL) << "Unsupported SIMD type"; 319 UNREACHABLE(); 320 } 321 } 322 323 void LocationsBuilderARMVIXL::VisitVecMul(HVecMul* instruction) { 324 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 325 } 326 327 void InstructionCodeGeneratorARMVIXL::VisitVecMul(HVecMul* instruction) { 328 LocationSummary* locations = instruction->GetLocations(); 329 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 330 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 331 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 332 switch (instruction->GetPackedType()) { 333 case Primitive::kPrimByte: 334 DCHECK_EQ(8u, instruction->GetVectorLength()); 335 __ Vmul(I8, dst, lhs, rhs); 336 break; 337 case Primitive::kPrimChar: 338 case Primitive::kPrimShort: 339 DCHECK_EQ(4u, instruction->GetVectorLength()); 340 __ Vmul(I16, dst, lhs, rhs); 341 break; 342 case Primitive::kPrimInt: 343 DCHECK_EQ(2u, instruction->GetVectorLength()); 344 __ Vmul(I32, dst, lhs, rhs); 345 break; 346 default: 347 LOG(FATAL) << "Unsupported SIMD type"; 348 UNREACHABLE(); 349 } 350 } 351 352 void LocationsBuilderARMVIXL::VisitVecDiv(HVecDiv* instruction) { 353 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 354 } 355 356 void InstructionCodeGeneratorARMVIXL::VisitVecDiv(HVecDiv* instruction) { 357 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 358 } 359 360 void LocationsBuilderARMVIXL::VisitVecMin(HVecMin* instruction) { 361 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 362 } 363 364 void InstructionCodeGeneratorARMVIXL::VisitVecMin(HVecMin* instruction) { 365 LocationSummary* locations = instruction->GetLocations(); 366 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 367 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 368 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 369 switch (instruction->GetPackedType()) { 370 case Primitive::kPrimByte: 371 DCHECK_EQ(8u, instruction->GetVectorLength()); 372 if (instruction->IsUnsigned()) { 373 __ Vmin(DataTypeValue::U8, dst, lhs, rhs); 374 } else { 375 __ Vmin(DataTypeValue::S8, dst, lhs, rhs); 376 } 377 break; 378 case Primitive::kPrimChar: 379 case Primitive::kPrimShort: 380 DCHECK_EQ(4u, instruction->GetVectorLength()); 381 if (instruction->IsUnsigned()) { 382 __ Vmin(DataTypeValue::U16, dst, lhs, rhs); 383 } else { 384 __ Vmin(DataTypeValue::S16, dst, lhs, rhs); 385 } 386 break; 387 case Primitive::kPrimInt: 388 DCHECK_EQ(2u, instruction->GetVectorLength()); 389 if (instruction->IsUnsigned()) { 390 __ Vmin(DataTypeValue::U32, dst, lhs, rhs); 391 } else { 392 __ Vmin(DataTypeValue::S32, dst, lhs, rhs); 393 } 394 break; 395 default: 396 LOG(FATAL) << "Unsupported SIMD type"; 397 UNREACHABLE(); 398 } 399 } 400 401 void LocationsBuilderARMVIXL::VisitVecMax(HVecMax* instruction) { 402 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 403 } 404 405 void InstructionCodeGeneratorARMVIXL::VisitVecMax(HVecMax* instruction) { 406 LocationSummary* locations = instruction->GetLocations(); 407 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 408 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 409 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 410 switch (instruction->GetPackedType()) { 411 case Primitive::kPrimByte: 412 DCHECK_EQ(8u, instruction->GetVectorLength()); 413 if (instruction->IsUnsigned()) { 414 __ Vmax(DataTypeValue::U8, dst, lhs, rhs); 415 } else { 416 __ Vmax(DataTypeValue::S8, dst, lhs, rhs); 417 } 418 break; 419 case Primitive::kPrimChar: 420 case Primitive::kPrimShort: 421 DCHECK_EQ(4u, instruction->GetVectorLength()); 422 if (instruction->IsUnsigned()) { 423 __ Vmax(DataTypeValue::U16, dst, lhs, rhs); 424 } else { 425 __ Vmax(DataTypeValue::S16, dst, lhs, rhs); 426 } 427 break; 428 case Primitive::kPrimInt: 429 DCHECK_EQ(2u, instruction->GetVectorLength()); 430 if (instruction->IsUnsigned()) { 431 __ Vmax(DataTypeValue::U32, dst, lhs, rhs); 432 } else { 433 __ Vmax(DataTypeValue::S32, dst, lhs, rhs); 434 } 435 break; 436 default: 437 LOG(FATAL) << "Unsupported SIMD type"; 438 UNREACHABLE(); 439 } 440 } 441 442 void LocationsBuilderARMVIXL::VisitVecAnd(HVecAnd* instruction) { 443 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 444 } 445 446 void InstructionCodeGeneratorARMVIXL::VisitVecAnd(HVecAnd* instruction) { 447 LocationSummary* locations = instruction->GetLocations(); 448 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 449 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 450 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 451 switch (instruction->GetPackedType()) { 452 case Primitive::kPrimBoolean: 453 case Primitive::kPrimByte: 454 case Primitive::kPrimChar: 455 case Primitive::kPrimShort: 456 case Primitive::kPrimInt: 457 __ Vand(I8, dst, lhs, rhs); 458 break; 459 default: 460 LOG(FATAL) << "Unsupported SIMD type"; 461 UNREACHABLE(); 462 } 463 } 464 465 void LocationsBuilderARMVIXL::VisitVecAndNot(HVecAndNot* instruction) { 466 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 467 } 468 469 void InstructionCodeGeneratorARMVIXL::VisitVecAndNot(HVecAndNot* instruction) { 470 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 471 } 472 473 void LocationsBuilderARMVIXL::VisitVecOr(HVecOr* instruction) { 474 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 475 } 476 477 void InstructionCodeGeneratorARMVIXL::VisitVecOr(HVecOr* instruction) { 478 LocationSummary* locations = instruction->GetLocations(); 479 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 480 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 481 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 482 switch (instruction->GetPackedType()) { 483 case Primitive::kPrimBoolean: 484 case Primitive::kPrimByte: 485 case Primitive::kPrimChar: 486 case Primitive::kPrimShort: 487 case Primitive::kPrimInt: 488 __ Vorr(I8, dst, lhs, rhs); 489 break; 490 default: 491 LOG(FATAL) << "Unsupported SIMD type"; 492 UNREACHABLE(); 493 } 494 } 495 496 void LocationsBuilderARMVIXL::VisitVecXor(HVecXor* instruction) { 497 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 498 } 499 500 void InstructionCodeGeneratorARMVIXL::VisitVecXor(HVecXor* instruction) { 501 LocationSummary* locations = instruction->GetLocations(); 502 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 503 vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1)); 504 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 505 switch (instruction->GetPackedType()) { 506 case Primitive::kPrimBoolean: 507 case Primitive::kPrimByte: 508 case Primitive::kPrimChar: 509 case Primitive::kPrimShort: 510 case Primitive::kPrimInt: 511 __ Veor(I8, dst, lhs, rhs); 512 break; 513 default: 514 LOG(FATAL) << "Unsupported SIMD type"; 515 UNREACHABLE(); 516 } 517 } 518 519 // Helper to set up locations for vector shift operations. 520 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) { 521 LocationSummary* locations = new (arena) LocationSummary(instruction); 522 switch (instruction->GetPackedType()) { 523 case Primitive::kPrimByte: 524 case Primitive::kPrimChar: 525 case Primitive::kPrimShort: 526 case Primitive::kPrimInt: 527 locations->SetInAt(0, Location::RequiresFpuRegister()); 528 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant())); 529 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 530 break; 531 default: 532 LOG(FATAL) << "Unsupported SIMD type"; 533 UNREACHABLE(); 534 } 535 } 536 537 void LocationsBuilderARMVIXL::VisitVecShl(HVecShl* instruction) { 538 CreateVecShiftLocations(GetGraph()->GetArena(), instruction); 539 } 540 541 void InstructionCodeGeneratorARMVIXL::VisitVecShl(HVecShl* instruction) { 542 LocationSummary* locations = instruction->GetLocations(); 543 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 544 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 545 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 546 switch (instruction->GetPackedType()) { 547 case Primitive::kPrimByte: 548 DCHECK_EQ(8u, instruction->GetVectorLength()); 549 __ Vshl(I8, dst, lhs, value); 550 break; 551 case Primitive::kPrimChar: 552 case Primitive::kPrimShort: 553 DCHECK_EQ(4u, instruction->GetVectorLength()); 554 __ Vshl(I16, dst, lhs, value); 555 break; 556 case Primitive::kPrimInt: 557 DCHECK_EQ(2u, instruction->GetVectorLength()); 558 __ Vshl(I32, dst, lhs, value); 559 break; 560 default: 561 LOG(FATAL) << "Unsupported SIMD type"; 562 UNREACHABLE(); 563 } 564 } 565 566 void LocationsBuilderARMVIXL::VisitVecShr(HVecShr* instruction) { 567 CreateVecShiftLocations(GetGraph()->GetArena(), instruction); 568 } 569 570 void InstructionCodeGeneratorARMVIXL::VisitVecShr(HVecShr* instruction) { 571 LocationSummary* locations = instruction->GetLocations(); 572 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 573 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 574 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 575 switch (instruction->GetPackedType()) { 576 case Primitive::kPrimByte: 577 DCHECK_EQ(8u, instruction->GetVectorLength()); 578 __ Vshr(DataTypeValue::S8, dst, lhs, value); 579 break; 580 case Primitive::kPrimChar: 581 case Primitive::kPrimShort: 582 DCHECK_EQ(4u, instruction->GetVectorLength()); 583 __ Vshr(DataTypeValue::S16, dst, lhs, value); 584 break; 585 case Primitive::kPrimInt: 586 DCHECK_EQ(2u, instruction->GetVectorLength()); 587 __ Vshr(DataTypeValue::S32, dst, lhs, value); 588 break; 589 default: 590 LOG(FATAL) << "Unsupported SIMD type"; 591 UNREACHABLE(); 592 } 593 } 594 595 void LocationsBuilderARMVIXL::VisitVecUShr(HVecUShr* instruction) { 596 CreateVecShiftLocations(GetGraph()->GetArena(), instruction); 597 } 598 599 void InstructionCodeGeneratorARMVIXL::VisitVecUShr(HVecUShr* instruction) { 600 LocationSummary* locations = instruction->GetLocations(); 601 vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0)); 602 vixl32::DRegister dst = DRegisterFrom(locations->Out()); 603 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 604 switch (instruction->GetPackedType()) { 605 case Primitive::kPrimByte: 606 DCHECK_EQ(8u, instruction->GetVectorLength()); 607 __ Vshr(DataTypeValue::U8, dst, lhs, value); 608 break; 609 case Primitive::kPrimChar: 610 case Primitive::kPrimShort: 611 DCHECK_EQ(4u, instruction->GetVectorLength()); 612 __ Vshr(DataTypeValue::U16, dst, lhs, value); 613 break; 614 case Primitive::kPrimInt: 615 DCHECK_EQ(2u, instruction->GetVectorLength()); 616 __ Vshr(DataTypeValue::U32, dst, lhs, value); 617 break; 618 default: 619 LOG(FATAL) << "Unsupported SIMD type"; 620 UNREACHABLE(); 621 } 622 } 623 624 void LocationsBuilderARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) { 625 LOG(FATAL) << "No SIMD for " << instr->GetId(); 626 } 627 628 void InstructionCodeGeneratorARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) { 629 LOG(FATAL) << "No SIMD for " << instr->GetId(); 630 } 631 632 // Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word 633 // size equals to 4). 634 static bool IsWordAligned(HVecMemoryOperation* instruction) { 635 return instruction->GetAlignment().IsAlignedAt(4u); 636 } 637 638 // Helper to set up locations for vector memory operations. 639 static void CreateVecMemLocations(ArenaAllocator* arena, 640 HVecMemoryOperation* instruction, 641 bool is_load) { 642 LocationSummary* locations = new (arena) LocationSummary(instruction); 643 switch (instruction->GetPackedType()) { 644 case Primitive::kPrimBoolean: 645 case Primitive::kPrimByte: 646 case Primitive::kPrimChar: 647 case Primitive::kPrimShort: 648 case Primitive::kPrimInt: 649 locations->SetInAt(0, Location::RequiresRegister()); 650 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 651 if (is_load) { 652 locations->SetOut(Location::RequiresFpuRegister()); 653 } else { 654 locations->SetInAt(2, Location::RequiresFpuRegister()); 655 } 656 break; 657 default: 658 LOG(FATAL) << "Unsupported SIMD type"; 659 UNREACHABLE(); 660 } 661 } 662 663 // Helper to set up locations for vector memory operations. Returns the memory operand and, 664 // if used, sets the output parameter scratch to a temporary register used in this operand, 665 // so that the client can release it right after the memory operand use. 666 MemOperand InstructionCodeGeneratorARMVIXL::VecAddress( 667 HVecMemoryOperation* instruction, 668 UseScratchRegisterScope* temps_scope, 669 /*out*/ vixl32::Register* scratch) { 670 LocationSummary* locations = instruction->GetLocations(); 671 vixl32::Register base = InputRegisterAt(instruction, 0); 672 673 Location index = locations->InAt(1); 674 size_t size = Primitive::ComponentSize(instruction->GetPackedType()); 675 uint32_t offset = mirror::Array::DataOffset(size).Uint32Value(); 676 size_t shift = ComponentSizeShiftWidth(size); 677 678 // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet. 679 DCHECK(!instruction->InputAt(0)->IsIntermediateAddress()); 680 681 if (index.IsConstant()) { 682 offset += Int64ConstantFrom(index) << shift; 683 return MemOperand(base, offset); 684 } else { 685 *scratch = temps_scope->Acquire(); 686 __ Add(*scratch, base, Operand(RegisterFrom(index), ShiftType::LSL, shift)); 687 688 return MemOperand(*scratch, offset); 689 } 690 } 691 692 AlignedMemOperand InstructionCodeGeneratorARMVIXL::VecAddressUnaligned( 693 HVecMemoryOperation* instruction, 694 UseScratchRegisterScope* temps_scope, 695 /*out*/ vixl32::Register* scratch) { 696 LocationSummary* locations = instruction->GetLocations(); 697 vixl32::Register base = InputRegisterAt(instruction, 0); 698 699 Location index = locations->InAt(1); 700 size_t size = Primitive::ComponentSize(instruction->GetPackedType()); 701 uint32_t offset = mirror::Array::DataOffset(size).Uint32Value(); 702 size_t shift = ComponentSizeShiftWidth(size); 703 704 // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet. 705 DCHECK(!instruction->InputAt(0)->IsIntermediateAddress()); 706 707 if (index.IsConstant()) { 708 offset += Int64ConstantFrom(index) << shift; 709 __ Add(*scratch, base, offset); 710 } else { 711 *scratch = temps_scope->Acquire(); 712 __ Add(*scratch, base, offset); 713 __ Add(*scratch, *scratch, Operand(RegisterFrom(index), ShiftType::LSL, shift)); 714 } 715 return AlignedMemOperand(*scratch, kNoAlignment); 716 } 717 718 void LocationsBuilderARMVIXL::VisitVecLoad(HVecLoad* instruction) { 719 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ true); 720 } 721 722 void InstructionCodeGeneratorARMVIXL::VisitVecLoad(HVecLoad* instruction) { 723 vixl32::DRegister reg = OutputDRegister(instruction); 724 UseScratchRegisterScope temps(GetVIXLAssembler()); 725 vixl32::Register scratch; 726 727 DCHECK(instruction->GetPackedType() != Primitive::kPrimChar || !instruction->IsStringCharAt()); 728 729 switch (instruction->GetPackedType()) { 730 case Primitive::kPrimBoolean: 731 case Primitive::kPrimByte: 732 DCHECK_EQ(8u, instruction->GetVectorLength()); 733 if (IsWordAligned(instruction)) { 734 __ Vldr(reg, VecAddress(instruction, &temps, &scratch)); 735 } else { 736 __ Vld1(Untyped8, 737 NeonRegisterList(reg, kMultipleLanes), 738 VecAddressUnaligned(instruction, &temps, &scratch)); 739 } 740 break; 741 case Primitive::kPrimChar: 742 case Primitive::kPrimShort: 743 DCHECK_EQ(4u, instruction->GetVectorLength()); 744 if (IsWordAligned(instruction)) { 745 __ Vldr(reg, VecAddress(instruction, &temps, &scratch)); 746 } else { 747 __ Vld1(Untyped16, 748 NeonRegisterList(reg, kMultipleLanes), 749 VecAddressUnaligned(instruction, &temps, &scratch)); 750 } 751 break; 752 case Primitive::kPrimInt: 753 DCHECK_EQ(2u, instruction->GetVectorLength()); 754 if (IsWordAligned(instruction)) { 755 __ Vldr(reg, VecAddress(instruction, &temps, &scratch)); 756 } else { 757 __ Vld1(Untyped32, 758 NeonRegisterList(reg, kMultipleLanes), 759 VecAddressUnaligned(instruction, &temps, &scratch)); 760 } 761 break; 762 default: 763 LOG(FATAL) << "Unsupported SIMD type"; 764 UNREACHABLE(); 765 } 766 } 767 768 void LocationsBuilderARMVIXL::VisitVecStore(HVecStore* instruction) { 769 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ false); 770 } 771 772 void InstructionCodeGeneratorARMVIXL::VisitVecStore(HVecStore* instruction) { 773 vixl32::DRegister reg = InputDRegisterAt(instruction, 2); 774 UseScratchRegisterScope temps(GetVIXLAssembler()); 775 vixl32::Register scratch; 776 switch (instruction->GetPackedType()) { 777 case Primitive::kPrimBoolean: 778 case Primitive::kPrimByte: 779 DCHECK_EQ(8u, instruction->GetVectorLength()); 780 if (IsWordAligned(instruction)) { 781 __ Vstr(reg, VecAddress(instruction, &temps, &scratch)); 782 } else { 783 __ Vst1(Untyped8, 784 NeonRegisterList(reg, kMultipleLanes), 785 VecAddressUnaligned(instruction, &temps, &scratch)); 786 } 787 break; 788 case Primitive::kPrimChar: 789 case Primitive::kPrimShort: 790 DCHECK_EQ(4u, instruction->GetVectorLength()); 791 if (IsWordAligned(instruction)) { 792 __ Vstr(reg, VecAddress(instruction, &temps, &scratch)); 793 } else { 794 __ Vst1(Untyped16, 795 NeonRegisterList(reg, kMultipleLanes), 796 VecAddressUnaligned(instruction, &temps, &scratch)); 797 } 798 break; 799 case Primitive::kPrimInt: 800 DCHECK_EQ(2u, instruction->GetVectorLength()); 801 if (IsWordAligned(instruction)) { 802 __ Vstr(reg, VecAddress(instruction, &temps, &scratch)); 803 } else { 804 __ Vst1(Untyped32, 805 NeonRegisterList(reg, kMultipleLanes), 806 VecAddressUnaligned(instruction, &temps, &scratch)); 807 } 808 break; 809 default: 810 LOG(FATAL) << "Unsupported SIMD type"; 811 UNREACHABLE(); 812 } 813 } 814 815 #undef __ 816 817 } // namespace arm 818 } // namespace art 819