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