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_mips64.h" 18 #include "mirror/array-inl.h" 19 20 namespace art { 21 namespace mips64 { 22 23 // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy. 24 #define __ down_cast<Mips64Assembler*>(GetAssembler())-> // NOLINT 25 26 VectorRegister VectorRegisterFrom(Location location) { 27 DCHECK(location.IsFpuRegister()); 28 return static_cast<VectorRegister>(location.AsFpuRegister<FpuRegister>()); 29 } 30 31 void LocationsBuilderMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) { 32 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction); 33 switch (instruction->GetPackedType()) { 34 case DataType::Type::kBool: 35 case DataType::Type::kUint8: 36 case DataType::Type::kInt8: 37 case DataType::Type::kUint16: 38 case DataType::Type::kInt16: 39 case DataType::Type::kInt32: 40 case DataType::Type::kInt64: 41 locations->SetInAt(0, Location::RequiresRegister()); 42 locations->SetOut(Location::RequiresFpuRegister()); 43 break; 44 case DataType::Type::kFloat32: 45 case DataType::Type::kFloat64: 46 locations->SetInAt(0, Location::RequiresFpuRegister()); 47 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 48 break; 49 default: 50 LOG(FATAL) << "Unsupported SIMD type"; 51 UNREACHABLE(); 52 } 53 } 54 55 void InstructionCodeGeneratorMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) { 56 LocationSummary* locations = instruction->GetLocations(); 57 VectorRegister dst = VectorRegisterFrom(locations->Out()); 58 switch (instruction->GetPackedType()) { 59 case DataType::Type::kBool: 60 case DataType::Type::kUint8: 61 case DataType::Type::kInt8: 62 DCHECK_EQ(16u, instruction->GetVectorLength()); 63 __ FillB(dst, locations->InAt(0).AsRegister<GpuRegister>()); 64 break; 65 case DataType::Type::kUint16: 66 case DataType::Type::kInt16: 67 DCHECK_EQ(8u, instruction->GetVectorLength()); 68 __ FillH(dst, locations->InAt(0).AsRegister<GpuRegister>()); 69 break; 70 case DataType::Type::kInt32: 71 DCHECK_EQ(4u, instruction->GetVectorLength()); 72 __ FillW(dst, locations->InAt(0).AsRegister<GpuRegister>()); 73 break; 74 case DataType::Type::kInt64: 75 DCHECK_EQ(2u, instruction->GetVectorLength()); 76 __ FillD(dst, locations->InAt(0).AsRegister<GpuRegister>()); 77 break; 78 case DataType::Type::kFloat32: 79 DCHECK_EQ(4u, instruction->GetVectorLength()); 80 __ ReplicateFPToVectorRegister(dst, 81 locations->InAt(0).AsFpuRegister<FpuRegister>(), 82 /* is_double */ false); 83 break; 84 case DataType::Type::kFloat64: 85 DCHECK_EQ(2u, instruction->GetVectorLength()); 86 __ ReplicateFPToVectorRegister(dst, 87 locations->InAt(0).AsFpuRegister<FpuRegister>(), 88 /* is_double */ true); 89 break; 90 default: 91 LOG(FATAL) << "Unsupported SIMD type"; 92 UNREACHABLE(); 93 } 94 } 95 96 void LocationsBuilderMIPS64::VisitVecExtractScalar(HVecExtractScalar* instruction) { 97 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction); 98 switch (instruction->GetPackedType()) { 99 case DataType::Type::kBool: 100 case DataType::Type::kUint8: 101 case DataType::Type::kInt8: 102 case DataType::Type::kUint16: 103 case DataType::Type::kInt16: 104 case DataType::Type::kInt32: 105 case DataType::Type::kInt64: 106 locations->SetInAt(0, Location::RequiresFpuRegister()); 107 locations->SetOut(Location::RequiresRegister()); 108 break; 109 case DataType::Type::kFloat32: 110 case DataType::Type::kFloat64: 111 locations->SetInAt(0, Location::RequiresFpuRegister()); 112 locations->SetOut(Location::SameAsFirstInput()); 113 break; 114 default: 115 LOG(FATAL) << "Unsupported SIMD type"; 116 UNREACHABLE(); 117 } 118 } 119 120 void InstructionCodeGeneratorMIPS64::VisitVecExtractScalar(HVecExtractScalar* instruction) { 121 LocationSummary* locations = instruction->GetLocations(); 122 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 123 switch (instruction->GetPackedType()) { 124 case DataType::Type::kInt32: 125 DCHECK_EQ(4u, instruction->GetVectorLength()); 126 __ Copy_sW(locations->Out().AsRegister<GpuRegister>(), src, 0); 127 break; 128 case DataType::Type::kInt64: 129 DCHECK_EQ(2u, instruction->GetVectorLength()); 130 __ Copy_sD(locations->Out().AsRegister<GpuRegister>(), src, 0); 131 break; 132 case DataType::Type::kFloat32: 133 case DataType::Type::kFloat64: 134 DCHECK_LE(2u, instruction->GetVectorLength()); 135 DCHECK_LE(instruction->GetVectorLength(), 4u); 136 DCHECK(locations->InAt(0).Equals(locations->Out())); // no code required 137 break; 138 default: 139 LOG(FATAL) << "Unsupported SIMD type"; 140 UNREACHABLE(); 141 } 142 } 143 144 // Helper to set up locations for vector unary operations. 145 static void CreateVecUnOpLocations(ArenaAllocator* allocator, HVecUnaryOperation* instruction) { 146 LocationSummary* locations = new (allocator) LocationSummary(instruction); 147 DataType::Type type = instruction->GetPackedType(); 148 switch (type) { 149 case DataType::Type::kBool: 150 locations->SetInAt(0, Location::RequiresFpuRegister()); 151 locations->SetOut(Location::RequiresFpuRegister(), 152 instruction->IsVecNot() ? Location::kOutputOverlap 153 : Location::kNoOutputOverlap); 154 break; 155 case DataType::Type::kUint8: 156 case DataType::Type::kInt8: 157 case DataType::Type::kUint16: 158 case DataType::Type::kInt16: 159 case DataType::Type::kInt32: 160 case DataType::Type::kInt64: 161 case DataType::Type::kFloat32: 162 case DataType::Type::kFloat64: 163 locations->SetInAt(0, Location::RequiresFpuRegister()); 164 locations->SetOut(Location::RequiresFpuRegister(), 165 (instruction->IsVecNeg() || instruction->IsVecAbs() || 166 (instruction->IsVecReduce() && type == DataType::Type::kInt64)) 167 ? Location::kOutputOverlap 168 : Location::kNoOutputOverlap); 169 break; 170 default: 171 LOG(FATAL) << "Unsupported SIMD type"; 172 UNREACHABLE(); 173 } 174 } 175 176 void LocationsBuilderMIPS64::VisitVecReduce(HVecReduce* instruction) { 177 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction); 178 } 179 180 void InstructionCodeGeneratorMIPS64::VisitVecReduce(HVecReduce* instruction) { 181 LocationSummary* locations = instruction->GetLocations(); 182 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 183 VectorRegister dst = VectorRegisterFrom(locations->Out()); 184 VectorRegister tmp = static_cast<VectorRegister>(FTMP); 185 switch (instruction->GetPackedType()) { 186 case DataType::Type::kInt32: 187 DCHECK_EQ(4u, instruction->GetVectorLength()); 188 switch (instruction->GetKind()) { 189 case HVecReduce::kSum: 190 __ Hadd_sD(tmp, src, src); 191 __ IlvlD(dst, tmp, tmp); 192 __ AddvW(dst, dst, tmp); 193 break; 194 case HVecReduce::kMin: 195 __ IlvodW(tmp, src, src); 196 __ Min_sW(tmp, src, tmp); 197 __ IlvlW(dst, tmp, tmp); 198 __ Min_sW(dst, dst, tmp); 199 break; 200 case HVecReduce::kMax: 201 __ IlvodW(tmp, src, src); 202 __ Max_sW(tmp, src, tmp); 203 __ IlvlW(dst, tmp, tmp); 204 __ Max_sW(dst, dst, tmp); 205 break; 206 } 207 break; 208 case DataType::Type::kInt64: 209 DCHECK_EQ(2u, instruction->GetVectorLength()); 210 switch (instruction->GetKind()) { 211 case HVecReduce::kSum: 212 __ IlvlD(dst, src, src); 213 __ AddvD(dst, dst, src); 214 break; 215 case HVecReduce::kMin: 216 __ IlvlD(dst, src, src); 217 __ Min_sD(dst, dst, src); 218 break; 219 case HVecReduce::kMax: 220 __ IlvlD(dst, src, src); 221 __ Max_sD(dst, dst, src); 222 break; 223 } 224 break; 225 default: 226 LOG(FATAL) << "Unsupported SIMD type"; 227 UNREACHABLE(); 228 } 229 } 230 231 void LocationsBuilderMIPS64::VisitVecCnv(HVecCnv* instruction) { 232 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction); 233 } 234 235 void InstructionCodeGeneratorMIPS64::VisitVecCnv(HVecCnv* instruction) { 236 LocationSummary* locations = instruction->GetLocations(); 237 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 238 VectorRegister dst = VectorRegisterFrom(locations->Out()); 239 DataType::Type from = instruction->GetInputType(); 240 DataType::Type to = instruction->GetResultType(); 241 if (from == DataType::Type::kInt32 && to == DataType::Type::kFloat32) { 242 DCHECK_EQ(4u, instruction->GetVectorLength()); 243 __ Ffint_sW(dst, src); 244 } else { 245 LOG(FATAL) << "Unsupported SIMD type"; 246 UNREACHABLE(); 247 } 248 } 249 250 void LocationsBuilderMIPS64::VisitVecNeg(HVecNeg* instruction) { 251 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction); 252 } 253 254 void InstructionCodeGeneratorMIPS64::VisitVecNeg(HVecNeg* instruction) { 255 LocationSummary* locations = instruction->GetLocations(); 256 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 257 VectorRegister dst = VectorRegisterFrom(locations->Out()); 258 switch (instruction->GetPackedType()) { 259 case DataType::Type::kUint8: 260 case DataType::Type::kInt8: 261 DCHECK_EQ(16u, instruction->GetVectorLength()); 262 __ FillB(dst, ZERO); 263 __ SubvB(dst, dst, src); 264 break; 265 case DataType::Type::kUint16: 266 case DataType::Type::kInt16: 267 DCHECK_EQ(8u, instruction->GetVectorLength()); 268 __ FillH(dst, ZERO); 269 __ SubvH(dst, dst, src); 270 break; 271 case DataType::Type::kInt32: 272 DCHECK_EQ(4u, instruction->GetVectorLength()); 273 __ FillW(dst, ZERO); 274 __ SubvW(dst, dst, src); 275 break; 276 case DataType::Type::kInt64: 277 DCHECK_EQ(2u, instruction->GetVectorLength()); 278 __ FillD(dst, ZERO); 279 __ SubvD(dst, dst, src); 280 break; 281 case DataType::Type::kFloat32: 282 DCHECK_EQ(4u, instruction->GetVectorLength()); 283 __ FillW(dst, ZERO); 284 __ FsubW(dst, dst, src); 285 break; 286 case DataType::Type::kFloat64: 287 DCHECK_EQ(2u, instruction->GetVectorLength()); 288 __ FillD(dst, ZERO); 289 __ FsubD(dst, dst, src); 290 break; 291 default: 292 LOG(FATAL) << "Unsupported SIMD type"; 293 UNREACHABLE(); 294 } 295 } 296 297 void LocationsBuilderMIPS64::VisitVecAbs(HVecAbs* instruction) { 298 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction); 299 } 300 301 void InstructionCodeGeneratorMIPS64::VisitVecAbs(HVecAbs* instruction) { 302 LocationSummary* locations = instruction->GetLocations(); 303 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 304 VectorRegister dst = VectorRegisterFrom(locations->Out()); 305 switch (instruction->GetPackedType()) { 306 case DataType::Type::kInt8: 307 DCHECK_EQ(16u, instruction->GetVectorLength()); 308 __ FillB(dst, ZERO); // all zeroes 309 __ Add_aB(dst, dst, src); // dst = abs(0) + abs(src) 310 break; 311 case DataType::Type::kInt16: 312 DCHECK_EQ(8u, instruction->GetVectorLength()); 313 __ FillH(dst, ZERO); // all zeroes 314 __ Add_aH(dst, dst, src); // dst = abs(0) + abs(src) 315 break; 316 case DataType::Type::kInt32: 317 DCHECK_EQ(4u, instruction->GetVectorLength()); 318 __ FillW(dst, ZERO); // all zeroes 319 __ Add_aW(dst, dst, src); // dst = abs(0) + abs(src) 320 break; 321 case DataType::Type::kInt64: 322 DCHECK_EQ(2u, instruction->GetVectorLength()); 323 __ FillD(dst, ZERO); // all zeroes 324 __ Add_aD(dst, dst, src); // dst = abs(0) + abs(src) 325 break; 326 case DataType::Type::kFloat32: 327 DCHECK_EQ(4u, instruction->GetVectorLength()); 328 __ LdiW(dst, -1); // all ones 329 __ SrliW(dst, dst, 1); 330 __ AndV(dst, dst, src); 331 break; 332 case DataType::Type::kFloat64: 333 DCHECK_EQ(2u, instruction->GetVectorLength()); 334 __ LdiD(dst, -1); // all ones 335 __ SrliD(dst, dst, 1); 336 __ AndV(dst, dst, src); 337 break; 338 default: 339 LOG(FATAL) << "Unsupported SIMD type"; 340 UNREACHABLE(); 341 } 342 } 343 344 void LocationsBuilderMIPS64::VisitVecNot(HVecNot* instruction) { 345 CreateVecUnOpLocations(GetGraph()->GetAllocator(), instruction); 346 } 347 348 void InstructionCodeGeneratorMIPS64::VisitVecNot(HVecNot* instruction) { 349 LocationSummary* locations = instruction->GetLocations(); 350 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 351 VectorRegister dst = VectorRegisterFrom(locations->Out()); 352 switch (instruction->GetPackedType()) { 353 case DataType::Type::kBool: // special case boolean-not 354 DCHECK_EQ(16u, instruction->GetVectorLength()); 355 __ LdiB(dst, 1); 356 __ XorV(dst, dst, src); 357 break; 358 case DataType::Type::kUint8: 359 case DataType::Type::kInt8: 360 case DataType::Type::kUint16: 361 case DataType::Type::kInt16: 362 case DataType::Type::kInt32: 363 case DataType::Type::kInt64: 364 case DataType::Type::kFloat32: 365 case DataType::Type::kFloat64: 366 DCHECK_LE(2u, instruction->GetVectorLength()); 367 DCHECK_LE(instruction->GetVectorLength(), 16u); 368 __ NorV(dst, src, src); // lanes do not matter 369 break; 370 default: 371 LOG(FATAL) << "Unsupported SIMD type"; 372 UNREACHABLE(); 373 } 374 } 375 376 // Helper to set up locations for vector binary operations. 377 static void CreateVecBinOpLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) { 378 LocationSummary* locations = new (allocator) LocationSummary(instruction); 379 switch (instruction->GetPackedType()) { 380 case DataType::Type::kBool: 381 case DataType::Type::kUint8: 382 case DataType::Type::kInt8: 383 case DataType::Type::kUint16: 384 case DataType::Type::kInt16: 385 case DataType::Type::kInt32: 386 case DataType::Type::kInt64: 387 case DataType::Type::kFloat32: 388 case DataType::Type::kFloat64: 389 locations->SetInAt(0, Location::RequiresFpuRegister()); 390 locations->SetInAt(1, Location::RequiresFpuRegister()); 391 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 392 break; 393 default: 394 LOG(FATAL) << "Unsupported SIMD type"; 395 UNREACHABLE(); 396 } 397 } 398 399 void LocationsBuilderMIPS64::VisitVecAdd(HVecAdd* instruction) { 400 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 401 } 402 403 void InstructionCodeGeneratorMIPS64::VisitVecAdd(HVecAdd* instruction) { 404 LocationSummary* locations = instruction->GetLocations(); 405 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 406 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 407 VectorRegister dst = VectorRegisterFrom(locations->Out()); 408 switch (instruction->GetPackedType()) { 409 case DataType::Type::kUint8: 410 case DataType::Type::kInt8: 411 DCHECK_EQ(16u, instruction->GetVectorLength()); 412 __ AddvB(dst, lhs, rhs); 413 break; 414 case DataType::Type::kUint16: 415 case DataType::Type::kInt16: 416 DCHECK_EQ(8u, instruction->GetVectorLength()); 417 __ AddvH(dst, lhs, rhs); 418 break; 419 case DataType::Type::kInt32: 420 DCHECK_EQ(4u, instruction->GetVectorLength()); 421 __ AddvW(dst, lhs, rhs); 422 break; 423 case DataType::Type::kInt64: 424 DCHECK_EQ(2u, instruction->GetVectorLength()); 425 __ AddvD(dst, lhs, rhs); 426 break; 427 case DataType::Type::kFloat32: 428 DCHECK_EQ(4u, instruction->GetVectorLength()); 429 __ FaddW(dst, lhs, rhs); 430 break; 431 case DataType::Type::kFloat64: 432 DCHECK_EQ(2u, instruction->GetVectorLength()); 433 __ FaddD(dst, lhs, rhs); 434 break; 435 default: 436 LOG(FATAL) << "Unsupported SIMD type"; 437 UNREACHABLE(); 438 } 439 } 440 441 void LocationsBuilderMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) { 442 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 443 } 444 445 void InstructionCodeGeneratorMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) { 446 LocationSummary* locations = instruction->GetLocations(); 447 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 448 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 449 VectorRegister dst = VectorRegisterFrom(locations->Out()); 450 switch (instruction->GetPackedType()) { 451 case DataType::Type::kUint8: 452 DCHECK_EQ(16u, instruction->GetVectorLength()); 453 instruction->IsRounded() 454 ? __ Aver_uB(dst, lhs, rhs) 455 : __ Ave_uB(dst, lhs, rhs); 456 break; 457 case DataType::Type::kInt8: 458 DCHECK_EQ(16u, instruction->GetVectorLength()); 459 instruction->IsRounded() 460 ? __ Aver_sB(dst, lhs, rhs) 461 : __ Ave_sB(dst, lhs, rhs); 462 break; 463 case DataType::Type::kUint16: 464 DCHECK_EQ(8u, instruction->GetVectorLength()); 465 instruction->IsRounded() 466 ? __ Aver_uH(dst, lhs, rhs) 467 : __ Ave_uH(dst, lhs, rhs); 468 break; 469 case DataType::Type::kInt16: 470 DCHECK_EQ(8u, instruction->GetVectorLength()); 471 instruction->IsRounded() 472 ? __ Aver_sH(dst, lhs, rhs) 473 : __ Ave_sH(dst, lhs, rhs); 474 break; 475 default: 476 LOG(FATAL) << "Unsupported SIMD type"; 477 UNREACHABLE(); 478 } 479 } 480 481 void LocationsBuilderMIPS64::VisitVecSub(HVecSub* instruction) { 482 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 483 } 484 485 void InstructionCodeGeneratorMIPS64::VisitVecSub(HVecSub* instruction) { 486 LocationSummary* locations = instruction->GetLocations(); 487 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 488 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 489 VectorRegister dst = VectorRegisterFrom(locations->Out()); 490 switch (instruction->GetPackedType()) { 491 case DataType::Type::kUint8: 492 case DataType::Type::kInt8: 493 DCHECK_EQ(16u, instruction->GetVectorLength()); 494 __ SubvB(dst, lhs, rhs); 495 break; 496 case DataType::Type::kUint16: 497 case DataType::Type::kInt16: 498 DCHECK_EQ(8u, instruction->GetVectorLength()); 499 __ SubvH(dst, lhs, rhs); 500 break; 501 case DataType::Type::kInt32: 502 DCHECK_EQ(4u, instruction->GetVectorLength()); 503 __ SubvW(dst, lhs, rhs); 504 break; 505 case DataType::Type::kInt64: 506 DCHECK_EQ(2u, instruction->GetVectorLength()); 507 __ SubvD(dst, lhs, rhs); 508 break; 509 case DataType::Type::kFloat32: 510 DCHECK_EQ(4u, instruction->GetVectorLength()); 511 __ FsubW(dst, lhs, rhs); 512 break; 513 case DataType::Type::kFloat64: 514 DCHECK_EQ(2u, instruction->GetVectorLength()); 515 __ FsubD(dst, lhs, rhs); 516 break; 517 default: 518 LOG(FATAL) << "Unsupported SIMD type"; 519 UNREACHABLE(); 520 } 521 } 522 523 void LocationsBuilderMIPS64::VisitVecMul(HVecMul* instruction) { 524 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 525 } 526 527 void InstructionCodeGeneratorMIPS64::VisitVecMul(HVecMul* instruction) { 528 LocationSummary* locations = instruction->GetLocations(); 529 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 530 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 531 VectorRegister dst = VectorRegisterFrom(locations->Out()); 532 switch (instruction->GetPackedType()) { 533 case DataType::Type::kUint8: 534 case DataType::Type::kInt8: 535 DCHECK_EQ(16u, instruction->GetVectorLength()); 536 __ MulvB(dst, lhs, rhs); 537 break; 538 case DataType::Type::kUint16: 539 case DataType::Type::kInt16: 540 DCHECK_EQ(8u, instruction->GetVectorLength()); 541 __ MulvH(dst, lhs, rhs); 542 break; 543 case DataType::Type::kInt32: 544 DCHECK_EQ(4u, instruction->GetVectorLength()); 545 __ MulvW(dst, lhs, rhs); 546 break; 547 case DataType::Type::kInt64: 548 DCHECK_EQ(2u, instruction->GetVectorLength()); 549 __ MulvD(dst, lhs, rhs); 550 break; 551 case DataType::Type::kFloat32: 552 DCHECK_EQ(4u, instruction->GetVectorLength()); 553 __ FmulW(dst, lhs, rhs); 554 break; 555 case DataType::Type::kFloat64: 556 DCHECK_EQ(2u, instruction->GetVectorLength()); 557 __ FmulD(dst, lhs, rhs); 558 break; 559 default: 560 LOG(FATAL) << "Unsupported SIMD type"; 561 UNREACHABLE(); 562 } 563 } 564 565 void LocationsBuilderMIPS64::VisitVecDiv(HVecDiv* instruction) { 566 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 567 } 568 569 void InstructionCodeGeneratorMIPS64::VisitVecDiv(HVecDiv* instruction) { 570 LocationSummary* locations = instruction->GetLocations(); 571 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 572 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 573 VectorRegister dst = VectorRegisterFrom(locations->Out()); 574 switch (instruction->GetPackedType()) { 575 case DataType::Type::kFloat32: 576 DCHECK_EQ(4u, instruction->GetVectorLength()); 577 __ FdivW(dst, lhs, rhs); 578 break; 579 case DataType::Type::kFloat64: 580 DCHECK_EQ(2u, instruction->GetVectorLength()); 581 __ FdivD(dst, lhs, rhs); 582 break; 583 default: 584 LOG(FATAL) << "Unsupported SIMD type"; 585 UNREACHABLE(); 586 } 587 } 588 589 void LocationsBuilderMIPS64::VisitVecMin(HVecMin* instruction) { 590 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 591 } 592 593 void InstructionCodeGeneratorMIPS64::VisitVecMin(HVecMin* instruction) { 594 LocationSummary* locations = instruction->GetLocations(); 595 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 596 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 597 VectorRegister dst = VectorRegisterFrom(locations->Out()); 598 switch (instruction->GetPackedType()) { 599 case DataType::Type::kUint8: 600 DCHECK_EQ(16u, instruction->GetVectorLength()); 601 __ Min_uB(dst, lhs, rhs); 602 break; 603 case DataType::Type::kInt8: 604 DCHECK_EQ(16u, instruction->GetVectorLength()); 605 __ Min_sB(dst, lhs, rhs); 606 break; 607 case DataType::Type::kUint16: 608 DCHECK_EQ(8u, instruction->GetVectorLength()); 609 __ Min_uH(dst, lhs, rhs); 610 break; 611 case DataType::Type::kInt16: 612 DCHECK_EQ(8u, instruction->GetVectorLength()); 613 __ Min_sH(dst, lhs, rhs); 614 break; 615 case DataType::Type::kUint32: 616 DCHECK_EQ(4u, instruction->GetVectorLength()); 617 __ Min_uW(dst, lhs, rhs); 618 break; 619 case DataType::Type::kInt32: 620 DCHECK_EQ(4u, instruction->GetVectorLength()); 621 __ Min_sW(dst, lhs, rhs); 622 break; 623 case DataType::Type::kUint64: 624 DCHECK_EQ(2u, instruction->GetVectorLength()); 625 __ Min_uD(dst, lhs, rhs); 626 break; 627 case DataType::Type::kInt64: 628 DCHECK_EQ(2u, instruction->GetVectorLength()); 629 __ Min_sD(dst, lhs, rhs); 630 break; 631 // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value. 632 // TODO: Fix min(x, NaN) cases for float and double. 633 case DataType::Type::kFloat32: 634 DCHECK_EQ(4u, instruction->GetVectorLength()); 635 __ FminW(dst, lhs, rhs); 636 break; 637 case DataType::Type::kFloat64: 638 DCHECK_EQ(2u, instruction->GetVectorLength()); 639 __ FminD(dst, lhs, rhs); 640 break; 641 default: 642 LOG(FATAL) << "Unsupported SIMD type"; 643 UNREACHABLE(); 644 } 645 } 646 647 void LocationsBuilderMIPS64::VisitVecMax(HVecMax* instruction) { 648 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 649 } 650 651 void InstructionCodeGeneratorMIPS64::VisitVecMax(HVecMax* instruction) { 652 LocationSummary* locations = instruction->GetLocations(); 653 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 654 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 655 VectorRegister dst = VectorRegisterFrom(locations->Out()); 656 switch (instruction->GetPackedType()) { 657 case DataType::Type::kUint8: 658 DCHECK_EQ(16u, instruction->GetVectorLength()); 659 __ Max_uB(dst, lhs, rhs); 660 break; 661 case DataType::Type::kInt8: 662 DCHECK_EQ(16u, instruction->GetVectorLength()); 663 __ Max_sB(dst, lhs, rhs); 664 break; 665 case DataType::Type::kUint16: 666 DCHECK_EQ(8u, instruction->GetVectorLength()); 667 __ Max_uH(dst, lhs, rhs); 668 break; 669 case DataType::Type::kInt16: 670 DCHECK_EQ(8u, instruction->GetVectorLength()); 671 __ Max_sH(dst, lhs, rhs); 672 break; 673 case DataType::Type::kUint32: 674 DCHECK_EQ(4u, instruction->GetVectorLength()); 675 __ Max_uW(dst, lhs, rhs); 676 break; 677 case DataType::Type::kInt32: 678 DCHECK_EQ(4u, instruction->GetVectorLength()); 679 __ Max_sW(dst, lhs, rhs); 680 break; 681 case DataType::Type::kUint64: 682 DCHECK_EQ(2u, instruction->GetVectorLength()); 683 __ Max_uD(dst, lhs, rhs); 684 break; 685 case DataType::Type::kInt64: 686 DCHECK_EQ(2u, instruction->GetVectorLength()); 687 __ Max_sD(dst, lhs, rhs); 688 break; 689 // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value. 690 // TODO: Fix max(x, NaN) cases for float and double. 691 case DataType::Type::kFloat32: 692 DCHECK_EQ(4u, instruction->GetVectorLength()); 693 __ FmaxW(dst, lhs, rhs); 694 break; 695 case DataType::Type::kFloat64: 696 DCHECK_EQ(2u, instruction->GetVectorLength()); 697 __ FmaxD(dst, lhs, rhs); 698 break; 699 default: 700 LOG(FATAL) << "Unsupported SIMD type"; 701 UNREACHABLE(); 702 } 703 } 704 705 void LocationsBuilderMIPS64::VisitVecAnd(HVecAnd* instruction) { 706 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 707 } 708 709 void InstructionCodeGeneratorMIPS64::VisitVecAnd(HVecAnd* instruction) { 710 LocationSummary* locations = instruction->GetLocations(); 711 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 712 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 713 VectorRegister dst = VectorRegisterFrom(locations->Out()); 714 switch (instruction->GetPackedType()) { 715 case DataType::Type::kBool: 716 case DataType::Type::kUint8: 717 case DataType::Type::kInt8: 718 case DataType::Type::kUint16: 719 case DataType::Type::kInt16: 720 case DataType::Type::kInt32: 721 case DataType::Type::kInt64: 722 case DataType::Type::kFloat32: 723 case DataType::Type::kFloat64: 724 DCHECK_LE(2u, instruction->GetVectorLength()); 725 DCHECK_LE(instruction->GetVectorLength(), 16u); 726 __ AndV(dst, lhs, rhs); // lanes do not matter 727 break; 728 default: 729 LOG(FATAL) << "Unsupported SIMD type"; 730 UNREACHABLE(); 731 } 732 } 733 734 void LocationsBuilderMIPS64::VisitVecAndNot(HVecAndNot* instruction) { 735 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 736 } 737 738 void InstructionCodeGeneratorMIPS64::VisitVecAndNot(HVecAndNot* instruction) { 739 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 740 } 741 742 void LocationsBuilderMIPS64::VisitVecOr(HVecOr* instruction) { 743 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 744 } 745 746 void InstructionCodeGeneratorMIPS64::VisitVecOr(HVecOr* instruction) { 747 LocationSummary* locations = instruction->GetLocations(); 748 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 749 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 750 VectorRegister dst = VectorRegisterFrom(locations->Out()); 751 switch (instruction->GetPackedType()) { 752 case DataType::Type::kBool: 753 case DataType::Type::kUint8: 754 case DataType::Type::kInt8: 755 case DataType::Type::kUint16: 756 case DataType::Type::kInt16: 757 case DataType::Type::kInt32: 758 case DataType::Type::kInt64: 759 case DataType::Type::kFloat32: 760 case DataType::Type::kFloat64: 761 DCHECK_LE(2u, instruction->GetVectorLength()); 762 DCHECK_LE(instruction->GetVectorLength(), 16u); 763 __ OrV(dst, lhs, rhs); // lanes do not matter 764 break; 765 default: 766 LOG(FATAL) << "Unsupported SIMD type"; 767 UNREACHABLE(); 768 } 769 } 770 771 void LocationsBuilderMIPS64::VisitVecXor(HVecXor* instruction) { 772 CreateVecBinOpLocations(GetGraph()->GetAllocator(), instruction); 773 } 774 775 void InstructionCodeGeneratorMIPS64::VisitVecXor(HVecXor* instruction) { 776 LocationSummary* locations = instruction->GetLocations(); 777 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 778 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 779 VectorRegister dst = VectorRegisterFrom(locations->Out()); 780 switch (instruction->GetPackedType()) { 781 case DataType::Type::kBool: 782 case DataType::Type::kUint8: 783 case DataType::Type::kInt8: 784 case DataType::Type::kUint16: 785 case DataType::Type::kInt16: 786 case DataType::Type::kInt32: 787 case DataType::Type::kInt64: 788 case DataType::Type::kFloat32: 789 case DataType::Type::kFloat64: 790 DCHECK_LE(2u, instruction->GetVectorLength()); 791 DCHECK_LE(instruction->GetVectorLength(), 16u); 792 __ XorV(dst, lhs, rhs); // lanes do not matter 793 break; 794 default: 795 LOG(FATAL) << "Unsupported SIMD type"; 796 UNREACHABLE(); 797 } 798 } 799 800 // Helper to set up locations for vector shift operations. 801 static void CreateVecShiftLocations(ArenaAllocator* allocator, HVecBinaryOperation* instruction) { 802 LocationSummary* locations = new (allocator) LocationSummary(instruction); 803 switch (instruction->GetPackedType()) { 804 case DataType::Type::kUint8: 805 case DataType::Type::kInt8: 806 case DataType::Type::kUint16: 807 case DataType::Type::kInt16: 808 case DataType::Type::kInt32: 809 case DataType::Type::kInt64: 810 locations->SetInAt(0, Location::RequiresFpuRegister()); 811 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant())); 812 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 813 break; 814 default: 815 LOG(FATAL) << "Unsupported SIMD type"; 816 UNREACHABLE(); 817 } 818 } 819 820 void LocationsBuilderMIPS64::VisitVecShl(HVecShl* instruction) { 821 CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction); 822 } 823 824 void InstructionCodeGeneratorMIPS64::VisitVecShl(HVecShl* instruction) { 825 LocationSummary* locations = instruction->GetLocations(); 826 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 827 VectorRegister dst = VectorRegisterFrom(locations->Out()); 828 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 829 switch (instruction->GetPackedType()) { 830 case DataType::Type::kUint8: 831 case DataType::Type::kInt8: 832 DCHECK_EQ(16u, instruction->GetVectorLength()); 833 __ SlliB(dst, lhs, value); 834 break; 835 case DataType::Type::kUint16: 836 case DataType::Type::kInt16: 837 DCHECK_EQ(8u, instruction->GetVectorLength()); 838 __ SlliH(dst, lhs, value); 839 break; 840 case DataType::Type::kInt32: 841 DCHECK_EQ(4u, instruction->GetVectorLength()); 842 __ SlliW(dst, lhs, value); 843 break; 844 case DataType::Type::kInt64: 845 DCHECK_EQ(2u, instruction->GetVectorLength()); 846 __ SlliD(dst, lhs, value); 847 break; 848 default: 849 LOG(FATAL) << "Unsupported SIMD type"; 850 UNREACHABLE(); 851 } 852 } 853 854 void LocationsBuilderMIPS64::VisitVecShr(HVecShr* instruction) { 855 CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction); 856 } 857 858 void InstructionCodeGeneratorMIPS64::VisitVecShr(HVecShr* instruction) { 859 LocationSummary* locations = instruction->GetLocations(); 860 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 861 VectorRegister dst = VectorRegisterFrom(locations->Out()); 862 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 863 switch (instruction->GetPackedType()) { 864 case DataType::Type::kUint8: 865 case DataType::Type::kInt8: 866 DCHECK_EQ(16u, instruction->GetVectorLength()); 867 __ SraiB(dst, lhs, value); 868 break; 869 case DataType::Type::kUint16: 870 case DataType::Type::kInt16: 871 DCHECK_EQ(8u, instruction->GetVectorLength()); 872 __ SraiH(dst, lhs, value); 873 break; 874 case DataType::Type::kInt32: 875 DCHECK_EQ(4u, instruction->GetVectorLength()); 876 __ SraiW(dst, lhs, value); 877 break; 878 case DataType::Type::kInt64: 879 DCHECK_EQ(2u, instruction->GetVectorLength()); 880 __ SraiD(dst, lhs, value); 881 break; 882 default: 883 LOG(FATAL) << "Unsupported SIMD type"; 884 UNREACHABLE(); 885 } 886 } 887 888 void LocationsBuilderMIPS64::VisitVecUShr(HVecUShr* instruction) { 889 CreateVecShiftLocations(GetGraph()->GetAllocator(), instruction); 890 } 891 892 void InstructionCodeGeneratorMIPS64::VisitVecUShr(HVecUShr* instruction) { 893 LocationSummary* locations = instruction->GetLocations(); 894 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 895 VectorRegister dst = VectorRegisterFrom(locations->Out()); 896 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 897 switch (instruction->GetPackedType()) { 898 case DataType::Type::kUint8: 899 case DataType::Type::kInt8: 900 DCHECK_EQ(16u, instruction->GetVectorLength()); 901 __ SrliB(dst, lhs, value); 902 break; 903 case DataType::Type::kUint16: 904 case DataType::Type::kInt16: 905 DCHECK_EQ(8u, instruction->GetVectorLength()); 906 __ SrliH(dst, lhs, value); 907 break; 908 case DataType::Type::kInt32: 909 DCHECK_EQ(4u, instruction->GetVectorLength()); 910 __ SrliW(dst, lhs, value); 911 break; 912 case DataType::Type::kInt64: 913 DCHECK_EQ(2u, instruction->GetVectorLength()); 914 __ SrliD(dst, lhs, value); 915 break; 916 default: 917 LOG(FATAL) << "Unsupported SIMD type"; 918 UNREACHABLE(); 919 } 920 } 921 922 void LocationsBuilderMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) { 923 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction); 924 925 DCHECK_EQ(1u, instruction->InputCount()); // only one input currently implemented 926 927 HInstruction* input = instruction->InputAt(0); 928 bool is_zero = IsZeroBitPattern(input); 929 930 switch (instruction->GetPackedType()) { 931 case DataType::Type::kBool: 932 case DataType::Type::kUint8: 933 case DataType::Type::kInt8: 934 case DataType::Type::kUint16: 935 case DataType::Type::kInt16: 936 case DataType::Type::kInt32: 937 case DataType::Type::kInt64: 938 locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant()) 939 : Location::RequiresRegister()); 940 locations->SetOut(Location::RequiresFpuRegister()); 941 break; 942 case DataType::Type::kFloat32: 943 case DataType::Type::kFloat64: 944 locations->SetInAt(0, is_zero ? Location::ConstantLocation(input->AsConstant()) 945 : Location::RequiresFpuRegister()); 946 locations->SetOut(Location::RequiresFpuRegister()); 947 break; 948 default: 949 LOG(FATAL) << "Unsupported SIMD type"; 950 UNREACHABLE(); 951 } 952 } 953 954 void InstructionCodeGeneratorMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) { 955 LocationSummary* locations = instruction->GetLocations(); 956 VectorRegister dst = VectorRegisterFrom(locations->Out()); 957 958 DCHECK_EQ(1u, instruction->InputCount()); // only one input currently implemented 959 960 // Zero out all other elements first. 961 __ FillW(dst, ZERO); 962 963 // Shorthand for any type of zero. 964 if (IsZeroBitPattern(instruction->InputAt(0))) { 965 return; 966 } 967 968 // Set required elements. 969 switch (instruction->GetPackedType()) { 970 case DataType::Type::kBool: 971 case DataType::Type::kUint8: 972 case DataType::Type::kInt8: 973 DCHECK_EQ(16u, instruction->GetVectorLength()); 974 __ InsertB(dst, locations->InAt(0).AsRegister<GpuRegister>(), 0); 975 break; 976 case DataType::Type::kUint16: 977 case DataType::Type::kInt16: 978 DCHECK_EQ(8u, instruction->GetVectorLength()); 979 __ InsertH(dst, locations->InAt(0).AsRegister<GpuRegister>(), 0); 980 break; 981 case DataType::Type::kInt32: 982 DCHECK_EQ(4u, instruction->GetVectorLength()); 983 __ InsertW(dst, locations->InAt(0).AsRegister<GpuRegister>(), 0); 984 break; 985 case DataType::Type::kInt64: 986 DCHECK_EQ(2u, instruction->GetVectorLength()); 987 __ InsertD(dst, locations->InAt(0).AsRegister<GpuRegister>(), 0); 988 break; 989 default: 990 LOG(FATAL) << "Unsupported SIMD type"; 991 UNREACHABLE(); 992 } 993 } 994 995 // Helper to set up locations for vector accumulations. 996 static void CreateVecAccumLocations(ArenaAllocator* allocator, HVecOperation* instruction) { 997 LocationSummary* locations = new (allocator) LocationSummary(instruction); 998 switch (instruction->GetPackedType()) { 999 case DataType::Type::kUint8: 1000 case DataType::Type::kInt8: 1001 case DataType::Type::kUint16: 1002 case DataType::Type::kInt16: 1003 case DataType::Type::kInt32: 1004 case DataType::Type::kInt64: 1005 locations->SetInAt(0, Location::RequiresFpuRegister()); 1006 locations->SetInAt(1, Location::RequiresFpuRegister()); 1007 locations->SetInAt(2, Location::RequiresFpuRegister()); 1008 locations->SetOut(Location::SameAsFirstInput()); 1009 break; 1010 default: 1011 LOG(FATAL) << "Unsupported SIMD type"; 1012 UNREACHABLE(); 1013 } 1014 } 1015 1016 void LocationsBuilderMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) { 1017 CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction); 1018 } 1019 1020 void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) { 1021 LocationSummary* locations = instruction->GetLocations(); 1022 VectorRegister acc = VectorRegisterFrom(locations->InAt(0)); 1023 VectorRegister left = VectorRegisterFrom(locations->InAt(1)); 1024 VectorRegister right = VectorRegisterFrom(locations->InAt(2)); 1025 switch (instruction->GetPackedType()) { 1026 case DataType::Type::kUint8: 1027 case DataType::Type::kInt8: 1028 DCHECK_EQ(16u, instruction->GetVectorLength()); 1029 if (instruction->GetOpKind() == HInstruction::kAdd) { 1030 __ MaddvB(acc, left, right); 1031 } else { 1032 __ MsubvB(acc, left, right); 1033 } 1034 break; 1035 case DataType::Type::kUint16: 1036 case DataType::Type::kInt16: 1037 DCHECK_EQ(8u, instruction->GetVectorLength()); 1038 if (instruction->GetOpKind() == HInstruction::kAdd) { 1039 __ MaddvH(acc, left, right); 1040 } else { 1041 __ MsubvH(acc, left, right); 1042 } 1043 break; 1044 case DataType::Type::kInt32: 1045 DCHECK_EQ(4u, instruction->GetVectorLength()); 1046 if (instruction->GetOpKind() == HInstruction::kAdd) { 1047 __ MaddvW(acc, left, right); 1048 } else { 1049 __ MsubvW(acc, left, right); 1050 } 1051 break; 1052 case DataType::Type::kInt64: 1053 DCHECK_EQ(2u, instruction->GetVectorLength()); 1054 if (instruction->GetOpKind() == HInstruction::kAdd) { 1055 __ MaddvD(acc, left, right); 1056 } else { 1057 __ MsubvD(acc, left, right); 1058 } 1059 break; 1060 default: 1061 LOG(FATAL) << "Unsupported SIMD type"; 1062 UNREACHABLE(); 1063 } 1064 } 1065 1066 void LocationsBuilderMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) { 1067 CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction); 1068 LocationSummary* locations = instruction->GetLocations(); 1069 // All conversions require at least one temporary register. 1070 locations->AddTemp(Location::RequiresFpuRegister()); 1071 // Some conversions require a second temporary register. 1072 HVecOperation* a = instruction->InputAt(1)->AsVecOperation(); 1073 HVecOperation* b = instruction->InputAt(2)->AsVecOperation(); 1074 DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()), 1075 HVecOperation::ToSignedType(b->GetPackedType())); 1076 switch (a->GetPackedType()) { 1077 case DataType::Type::kInt32: 1078 if (instruction->GetPackedType() == DataType::Type::kInt32) { 1079 break; 1080 } 1081 FALLTHROUGH_INTENDED; 1082 case DataType::Type::kUint8: 1083 case DataType::Type::kInt8: 1084 case DataType::Type::kUint16: 1085 case DataType::Type::kInt16: 1086 locations->AddTemp(Location::RequiresFpuRegister()); 1087 break; 1088 default: 1089 break; 1090 } 1091 } 1092 1093 void InstructionCodeGeneratorMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) { 1094 LocationSummary* locations = instruction->GetLocations(); 1095 VectorRegister acc = VectorRegisterFrom(locations->InAt(0)); 1096 VectorRegister left = VectorRegisterFrom(locations->InAt(1)); 1097 VectorRegister right = VectorRegisterFrom(locations->InAt(2)); 1098 VectorRegister tmp = static_cast<VectorRegister>(FTMP); 1099 VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0)); 1100 1101 DCHECK(locations->InAt(0).Equals(locations->Out())); 1102 1103 // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S). 1104 HVecOperation* a = instruction->InputAt(1)->AsVecOperation(); 1105 HVecOperation* b = instruction->InputAt(2)->AsVecOperation(); 1106 DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()), 1107 HVecOperation::ToSignedType(b->GetPackedType())); 1108 switch (a->GetPackedType()) { 1109 case DataType::Type::kUint8: 1110 case DataType::Type::kInt8: 1111 DCHECK_EQ(16u, a->GetVectorLength()); 1112 switch (instruction->GetPackedType()) { 1113 case DataType::Type::kUint16: 1114 case DataType::Type::kInt16: { 1115 DCHECK_EQ(8u, instruction->GetVectorLength()); 1116 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1)); 1117 __ FillB(tmp, ZERO); 1118 __ Hadd_sH(tmp1, left, tmp); 1119 __ Hadd_sH(tmp2, right, tmp); 1120 __ Asub_sH(tmp1, tmp1, tmp2); 1121 __ AddvH(acc, acc, tmp1); 1122 __ Hadd_sH(tmp1, tmp, left); 1123 __ Hadd_sH(tmp2, tmp, right); 1124 __ Asub_sH(tmp1, tmp1, tmp2); 1125 __ AddvH(acc, acc, tmp1); 1126 break; 1127 } 1128 case DataType::Type::kInt32: { 1129 DCHECK_EQ(4u, instruction->GetVectorLength()); 1130 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1)); 1131 __ FillB(tmp, ZERO); 1132 __ Hadd_sH(tmp1, left, tmp); 1133 __ Hadd_sH(tmp2, right, tmp); 1134 __ Asub_sH(tmp1, tmp1, tmp2); 1135 __ Hadd_sW(tmp1, tmp1, tmp1); 1136 __ AddvW(acc, acc, tmp1); 1137 __ Hadd_sH(tmp1, tmp, left); 1138 __ Hadd_sH(tmp2, tmp, right); 1139 __ Asub_sH(tmp1, tmp1, tmp2); 1140 __ Hadd_sW(tmp1, tmp1, tmp1); 1141 __ AddvW(acc, acc, tmp1); 1142 break; 1143 } 1144 case DataType::Type::kInt64: { 1145 DCHECK_EQ(2u, instruction->GetVectorLength()); 1146 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1)); 1147 __ FillB(tmp, ZERO); 1148 __ Hadd_sH(tmp1, left, tmp); 1149 __ Hadd_sH(tmp2, right, tmp); 1150 __ Asub_sH(tmp1, tmp1, tmp2); 1151 __ Hadd_sW(tmp1, tmp1, tmp1); 1152 __ Hadd_sD(tmp1, tmp1, tmp1); 1153 __ AddvD(acc, acc, tmp1); 1154 __ Hadd_sH(tmp1, tmp, left); 1155 __ Hadd_sH(tmp2, tmp, right); 1156 __ Asub_sH(tmp1, tmp1, tmp2); 1157 __ Hadd_sW(tmp1, tmp1, tmp1); 1158 __ Hadd_sD(tmp1, tmp1, tmp1); 1159 __ AddvD(acc, acc, tmp1); 1160 break; 1161 } 1162 default: 1163 LOG(FATAL) << "Unsupported SIMD type"; 1164 UNREACHABLE(); 1165 } 1166 break; 1167 case DataType::Type::kUint16: 1168 case DataType::Type::kInt16: 1169 DCHECK_EQ(8u, a->GetVectorLength()); 1170 switch (instruction->GetPackedType()) { 1171 case DataType::Type::kInt32: { 1172 DCHECK_EQ(4u, instruction->GetVectorLength()); 1173 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1)); 1174 __ FillH(tmp, ZERO); 1175 __ Hadd_sW(tmp1, left, tmp); 1176 __ Hadd_sW(tmp2, right, tmp); 1177 __ Asub_sW(tmp1, tmp1, tmp2); 1178 __ AddvW(acc, acc, tmp1); 1179 __ Hadd_sW(tmp1, tmp, left); 1180 __ Hadd_sW(tmp2, tmp, right); 1181 __ Asub_sW(tmp1, tmp1, tmp2); 1182 __ AddvW(acc, acc, tmp1); 1183 break; 1184 } 1185 case DataType::Type::kInt64: { 1186 DCHECK_EQ(2u, instruction->GetVectorLength()); 1187 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1)); 1188 __ FillH(tmp, ZERO); 1189 __ Hadd_sW(tmp1, left, tmp); 1190 __ Hadd_sW(tmp2, right, tmp); 1191 __ Asub_sW(tmp1, tmp1, tmp2); 1192 __ Hadd_sD(tmp1, tmp1, tmp1); 1193 __ AddvD(acc, acc, tmp1); 1194 __ Hadd_sW(tmp1, tmp, left); 1195 __ Hadd_sW(tmp2, tmp, right); 1196 __ Asub_sW(tmp1, tmp1, tmp2); 1197 __ Hadd_sD(tmp1, tmp1, tmp1); 1198 __ AddvD(acc, acc, tmp1); 1199 break; 1200 } 1201 default: 1202 LOG(FATAL) << "Unsupported SIMD type"; 1203 UNREACHABLE(); 1204 } 1205 break; 1206 case DataType::Type::kInt32: 1207 DCHECK_EQ(4u, a->GetVectorLength()); 1208 switch (instruction->GetPackedType()) { 1209 case DataType::Type::kInt32: { 1210 DCHECK_EQ(4u, instruction->GetVectorLength()); 1211 __ FillW(tmp, ZERO); 1212 __ SubvW(tmp1, left, right); 1213 __ Add_aW(tmp1, tmp1, tmp); 1214 __ AddvW(acc, acc, tmp1); 1215 break; 1216 } 1217 case DataType::Type::kInt64: { 1218 DCHECK_EQ(2u, instruction->GetVectorLength()); 1219 VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1)); 1220 __ FillW(tmp, ZERO); 1221 __ Hadd_sD(tmp1, left, tmp); 1222 __ Hadd_sD(tmp2, right, tmp); 1223 __ Asub_sD(tmp1, tmp1, tmp2); 1224 __ AddvD(acc, acc, tmp1); 1225 __ Hadd_sD(tmp1, tmp, left); 1226 __ Hadd_sD(tmp2, tmp, right); 1227 __ Asub_sD(tmp1, tmp1, tmp2); 1228 __ AddvD(acc, acc, tmp1); 1229 break; 1230 } 1231 default: 1232 LOG(FATAL) << "Unsupported SIMD type"; 1233 UNREACHABLE(); 1234 } 1235 break; 1236 case DataType::Type::kInt64: { 1237 DCHECK_EQ(2u, a->GetVectorLength()); 1238 switch (instruction->GetPackedType()) { 1239 case DataType::Type::kInt64: { 1240 DCHECK_EQ(2u, instruction->GetVectorLength()); 1241 __ FillD(tmp, ZERO); 1242 __ SubvD(tmp1, left, right); 1243 __ Add_aD(tmp1, tmp1, tmp); 1244 __ AddvD(acc, acc, tmp1); 1245 break; 1246 } 1247 default: 1248 LOG(FATAL) << "Unsupported SIMD type"; 1249 UNREACHABLE(); 1250 } 1251 break; 1252 } 1253 default: 1254 LOG(FATAL) << "Unsupported SIMD type"; 1255 UNREACHABLE(); 1256 } 1257 } 1258 1259 // Helper to set up locations for vector memory operations. 1260 static void CreateVecMemLocations(ArenaAllocator* allocator, 1261 HVecMemoryOperation* instruction, 1262 bool is_load) { 1263 LocationSummary* locations = new (allocator) LocationSummary(instruction); 1264 switch (instruction->GetPackedType()) { 1265 case DataType::Type::kBool: 1266 case DataType::Type::kUint8: 1267 case DataType::Type::kInt8: 1268 case DataType::Type::kUint16: 1269 case DataType::Type::kInt16: 1270 case DataType::Type::kInt32: 1271 case DataType::Type::kInt64: 1272 case DataType::Type::kFloat32: 1273 case DataType::Type::kFloat64: 1274 locations->SetInAt(0, Location::RequiresRegister()); 1275 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 1276 if (is_load) { 1277 locations->SetOut(Location::RequiresFpuRegister()); 1278 } else { 1279 locations->SetInAt(2, Location::RequiresFpuRegister()); 1280 } 1281 break; 1282 default: 1283 LOG(FATAL) << "Unsupported SIMD type"; 1284 UNREACHABLE(); 1285 } 1286 } 1287 1288 // Helper to prepare register and offset for vector memory operations. Returns the offset and sets 1289 // the output parameter adjusted_base to the original base or to a reserved temporary register (AT). 1290 int32_t InstructionCodeGeneratorMIPS64::VecAddress(LocationSummary* locations, 1291 size_t size, 1292 /* out */ GpuRegister* adjusted_base) { 1293 GpuRegister base = locations->InAt(0).AsRegister<GpuRegister>(); 1294 Location index = locations->InAt(1); 1295 int scale = TIMES_1; 1296 switch (size) { 1297 case 2: scale = TIMES_2; break; 1298 case 4: scale = TIMES_4; break; 1299 case 8: scale = TIMES_8; break; 1300 default: break; 1301 } 1302 int32_t offset = mirror::Array::DataOffset(size).Int32Value(); 1303 1304 if (index.IsConstant()) { 1305 offset += index.GetConstant()->AsIntConstant()->GetValue() << scale; 1306 __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale); 1307 *adjusted_base = base; 1308 } else { 1309 GpuRegister index_reg = index.AsRegister<GpuRegister>(); 1310 if (scale != TIMES_1) { 1311 __ Dlsa(AT, index_reg, base, scale); 1312 } else { 1313 __ Daddu(AT, base, index_reg); 1314 } 1315 *adjusted_base = AT; 1316 } 1317 return offset; 1318 } 1319 1320 void LocationsBuilderMIPS64::VisitVecLoad(HVecLoad* instruction) { 1321 CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load */ true); 1322 } 1323 1324 void InstructionCodeGeneratorMIPS64::VisitVecLoad(HVecLoad* instruction) { 1325 LocationSummary* locations = instruction->GetLocations(); 1326 size_t size = DataType::Size(instruction->GetPackedType()); 1327 VectorRegister reg = VectorRegisterFrom(locations->Out()); 1328 GpuRegister base; 1329 int32_t offset = VecAddress(locations, size, &base); 1330 switch (instruction->GetPackedType()) { 1331 case DataType::Type::kBool: 1332 case DataType::Type::kUint8: 1333 case DataType::Type::kInt8: 1334 DCHECK_EQ(16u, instruction->GetVectorLength()); 1335 __ LdB(reg, base, offset); 1336 break; 1337 case DataType::Type::kUint16: 1338 case DataType::Type::kInt16: 1339 // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned 1340 // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned 1341 // loads and stores. 1342 // TODO: Implement support for StringCharAt. 1343 DCHECK(!instruction->IsStringCharAt()); 1344 DCHECK_EQ(8u, instruction->GetVectorLength()); 1345 __ LdH(reg, base, offset); 1346 break; 1347 case DataType::Type::kInt32: 1348 case DataType::Type::kFloat32: 1349 DCHECK_EQ(4u, instruction->GetVectorLength()); 1350 __ LdW(reg, base, offset); 1351 break; 1352 case DataType::Type::kInt64: 1353 case DataType::Type::kFloat64: 1354 DCHECK_EQ(2u, instruction->GetVectorLength()); 1355 __ LdD(reg, base, offset); 1356 break; 1357 default: 1358 LOG(FATAL) << "Unsupported SIMD type"; 1359 UNREACHABLE(); 1360 } 1361 } 1362 1363 void LocationsBuilderMIPS64::VisitVecStore(HVecStore* instruction) { 1364 CreateVecMemLocations(GetGraph()->GetAllocator(), instruction, /* is_load */ false); 1365 } 1366 1367 void InstructionCodeGeneratorMIPS64::VisitVecStore(HVecStore* instruction) { 1368 LocationSummary* locations = instruction->GetLocations(); 1369 size_t size = DataType::Size(instruction->GetPackedType()); 1370 VectorRegister reg = VectorRegisterFrom(locations->InAt(2)); 1371 GpuRegister base; 1372 int32_t offset = VecAddress(locations, size, &base); 1373 switch (instruction->GetPackedType()) { 1374 case DataType::Type::kBool: 1375 case DataType::Type::kUint8: 1376 case DataType::Type::kInt8: 1377 DCHECK_EQ(16u, instruction->GetVectorLength()); 1378 __ StB(reg, base, offset); 1379 break; 1380 case DataType::Type::kUint16: 1381 case DataType::Type::kInt16: 1382 DCHECK_EQ(8u, instruction->GetVectorLength()); 1383 __ StH(reg, base, offset); 1384 break; 1385 case DataType::Type::kInt32: 1386 case DataType::Type::kFloat32: 1387 DCHECK_EQ(4u, instruction->GetVectorLength()); 1388 __ StW(reg, base, offset); 1389 break; 1390 case DataType::Type::kInt64: 1391 case DataType::Type::kFloat64: 1392 DCHECK_EQ(2u, instruction->GetVectorLength()); 1393 __ StD(reg, base, offset); 1394 break; 1395 default: 1396 LOG(FATAL) << "Unsupported SIMD type"; 1397 UNREACHABLE(); 1398 } 1399 } 1400 1401 #undef __ 1402 1403 } // namespace mips64 1404 } // namespace art 1405