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()->GetArena()) LocationSummary(instruction); 33 switch (instruction->GetPackedType()) { 34 case Primitive::kPrimBoolean: 35 case Primitive::kPrimByte: 36 case Primitive::kPrimChar: 37 case Primitive::kPrimShort: 38 case Primitive::kPrimInt: 39 case Primitive::kPrimLong: 40 locations->SetInAt(0, Location::RequiresRegister()); 41 locations->SetOut(Location::RequiresFpuRegister()); 42 break; 43 case Primitive::kPrimFloat: 44 case Primitive::kPrimDouble: 45 locations->SetInAt(0, Location::RequiresFpuRegister()); 46 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 47 break; 48 default: 49 LOG(FATAL) << "Unsupported SIMD type"; 50 UNREACHABLE(); 51 } 52 } 53 54 void InstructionCodeGeneratorMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) { 55 LocationSummary* locations = instruction->GetLocations(); 56 VectorRegister dst = VectorRegisterFrom(locations->Out()); 57 switch (instruction->GetPackedType()) { 58 case Primitive::kPrimBoolean: 59 case Primitive::kPrimByte: 60 DCHECK_EQ(16u, instruction->GetVectorLength()); 61 __ FillB(dst, locations->InAt(0).AsRegister<GpuRegister>()); 62 break; 63 case Primitive::kPrimChar: 64 case Primitive::kPrimShort: 65 DCHECK_EQ(8u, instruction->GetVectorLength()); 66 __ FillH(dst, locations->InAt(0).AsRegister<GpuRegister>()); 67 break; 68 case Primitive::kPrimInt: 69 DCHECK_EQ(4u, instruction->GetVectorLength()); 70 __ FillW(dst, locations->InAt(0).AsRegister<GpuRegister>()); 71 break; 72 case Primitive::kPrimLong: 73 DCHECK_EQ(2u, instruction->GetVectorLength()); 74 __ FillD(dst, locations->InAt(0).AsRegister<GpuRegister>()); 75 break; 76 case Primitive::kPrimFloat: 77 DCHECK_EQ(4u, instruction->GetVectorLength()); 78 __ ReplicateFPToVectorRegister(dst, 79 locations->InAt(0).AsFpuRegister<FpuRegister>(), 80 /* is_double */ false); 81 break; 82 case Primitive::kPrimDouble: 83 DCHECK_EQ(2u, instruction->GetVectorLength()); 84 __ ReplicateFPToVectorRegister(dst, 85 locations->InAt(0).AsFpuRegister<FpuRegister>(), 86 /* is_double */ true); 87 break; 88 default: 89 LOG(FATAL) << "Unsupported SIMD type"; 90 UNREACHABLE(); 91 } 92 } 93 94 void LocationsBuilderMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) { 95 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 96 } 97 98 void InstructionCodeGeneratorMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) { 99 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 100 } 101 102 void LocationsBuilderMIPS64::VisitVecSumReduce(HVecSumReduce* instruction) { 103 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 104 } 105 106 void InstructionCodeGeneratorMIPS64::VisitVecSumReduce(HVecSumReduce* instruction) { 107 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 108 } 109 110 // Helper to set up locations for vector unary operations. 111 static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* instruction) { 112 LocationSummary* locations = new (arena) LocationSummary(instruction); 113 switch (instruction->GetPackedType()) { 114 case Primitive::kPrimBoolean: 115 locations->SetInAt(0, Location::RequiresFpuRegister()); 116 locations->SetOut(Location::RequiresFpuRegister(), 117 instruction->IsVecNot() ? Location::kOutputOverlap 118 : Location::kNoOutputOverlap); 119 break; 120 case Primitive::kPrimByte: 121 case Primitive::kPrimChar: 122 case Primitive::kPrimShort: 123 case Primitive::kPrimInt: 124 case Primitive::kPrimLong: 125 case Primitive::kPrimFloat: 126 case Primitive::kPrimDouble: 127 locations->SetInAt(0, Location::RequiresFpuRegister()); 128 locations->SetOut(Location::RequiresFpuRegister(), 129 (instruction->IsVecNeg() || instruction->IsVecAbs()) 130 ? Location::kOutputOverlap 131 : Location::kNoOutputOverlap); 132 break; 133 default: 134 LOG(FATAL) << "Unsupported SIMD type"; 135 UNREACHABLE(); 136 } 137 } 138 139 void LocationsBuilderMIPS64::VisitVecCnv(HVecCnv* instruction) { 140 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 141 } 142 143 void InstructionCodeGeneratorMIPS64::VisitVecCnv(HVecCnv* instruction) { 144 LocationSummary* locations = instruction->GetLocations(); 145 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 146 VectorRegister dst = VectorRegisterFrom(locations->Out()); 147 Primitive::Type from = instruction->GetInputType(); 148 Primitive::Type to = instruction->GetResultType(); 149 if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) { 150 DCHECK_EQ(4u, instruction->GetVectorLength()); 151 __ Ffint_sW(dst, src); 152 } else { 153 LOG(FATAL) << "Unsupported SIMD type"; 154 UNREACHABLE(); 155 } 156 } 157 158 void LocationsBuilderMIPS64::VisitVecNeg(HVecNeg* instruction) { 159 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 160 } 161 162 void InstructionCodeGeneratorMIPS64::VisitVecNeg(HVecNeg* instruction) { 163 LocationSummary* locations = instruction->GetLocations(); 164 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 165 VectorRegister dst = VectorRegisterFrom(locations->Out()); 166 switch (instruction->GetPackedType()) { 167 case Primitive::kPrimByte: 168 DCHECK_EQ(16u, instruction->GetVectorLength()); 169 __ FillB(dst, ZERO); 170 __ SubvB(dst, dst, src); 171 break; 172 case Primitive::kPrimChar: 173 case Primitive::kPrimShort: 174 DCHECK_EQ(8u, instruction->GetVectorLength()); 175 __ FillH(dst, ZERO); 176 __ SubvH(dst, dst, src); 177 break; 178 case Primitive::kPrimInt: 179 DCHECK_EQ(4u, instruction->GetVectorLength()); 180 __ FillW(dst, ZERO); 181 __ SubvW(dst, dst, src); 182 break; 183 case Primitive::kPrimLong: 184 DCHECK_EQ(2u, instruction->GetVectorLength()); 185 __ FillD(dst, ZERO); 186 __ SubvD(dst, dst, src); 187 break; 188 case Primitive::kPrimFloat: 189 DCHECK_EQ(4u, instruction->GetVectorLength()); 190 __ FillW(dst, ZERO); 191 __ FsubW(dst, dst, src); 192 break; 193 case Primitive::kPrimDouble: 194 DCHECK_EQ(2u, instruction->GetVectorLength()); 195 __ FillD(dst, ZERO); 196 __ FsubD(dst, dst, src); 197 break; 198 default: 199 LOG(FATAL) << "Unsupported SIMD type"; 200 UNREACHABLE(); 201 } 202 } 203 204 void LocationsBuilderMIPS64::VisitVecAbs(HVecAbs* instruction) { 205 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 206 } 207 208 void InstructionCodeGeneratorMIPS64::VisitVecAbs(HVecAbs* instruction) { 209 LocationSummary* locations = instruction->GetLocations(); 210 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 211 VectorRegister dst = VectorRegisterFrom(locations->Out()); 212 switch (instruction->GetPackedType()) { 213 case Primitive::kPrimByte: 214 DCHECK_EQ(16u, instruction->GetVectorLength()); 215 __ FillB(dst, ZERO); // all zeroes 216 __ Add_aB(dst, dst, src); // dst = abs(0) + abs(src) 217 break; 218 case Primitive::kPrimChar: 219 case Primitive::kPrimShort: 220 DCHECK_EQ(8u, instruction->GetVectorLength()); 221 __ FillH(dst, ZERO); // all zeroes 222 __ Add_aH(dst, dst, src); // dst = abs(0) + abs(src) 223 break; 224 case Primitive::kPrimInt: 225 DCHECK_EQ(4u, instruction->GetVectorLength()); 226 __ FillW(dst, ZERO); // all zeroes 227 __ Add_aW(dst, dst, src); // dst = abs(0) + abs(src) 228 break; 229 case Primitive::kPrimLong: 230 DCHECK_EQ(2u, instruction->GetVectorLength()); 231 __ FillD(dst, ZERO); // all zeroes 232 __ Add_aD(dst, dst, src); // dst = abs(0) + abs(src) 233 break; 234 case Primitive::kPrimFloat: 235 DCHECK_EQ(4u, instruction->GetVectorLength()); 236 __ LdiW(dst, -1); // all ones 237 __ SrliW(dst, dst, 1); 238 __ AndV(dst, dst, src); 239 break; 240 case Primitive::kPrimDouble: 241 DCHECK_EQ(2u, instruction->GetVectorLength()); 242 __ LdiD(dst, -1); // all ones 243 __ SrliD(dst, dst, 1); 244 __ AndV(dst, dst, src); 245 break; 246 default: 247 LOG(FATAL) << "Unsupported SIMD type"; 248 UNREACHABLE(); 249 } 250 } 251 252 void LocationsBuilderMIPS64::VisitVecNot(HVecNot* instruction) { 253 CreateVecUnOpLocations(GetGraph()->GetArena(), instruction); 254 } 255 256 void InstructionCodeGeneratorMIPS64::VisitVecNot(HVecNot* instruction) { 257 LocationSummary* locations = instruction->GetLocations(); 258 VectorRegister src = VectorRegisterFrom(locations->InAt(0)); 259 VectorRegister dst = VectorRegisterFrom(locations->Out()); 260 switch (instruction->GetPackedType()) { 261 case Primitive::kPrimBoolean: // special case boolean-not 262 DCHECK_EQ(16u, instruction->GetVectorLength()); 263 __ LdiB(dst, 1); 264 __ XorV(dst, dst, src); 265 break; 266 case Primitive::kPrimByte: 267 case Primitive::kPrimChar: 268 case Primitive::kPrimShort: 269 case Primitive::kPrimInt: 270 case Primitive::kPrimLong: 271 case Primitive::kPrimFloat: 272 case Primitive::kPrimDouble: 273 DCHECK_LE(2u, instruction->GetVectorLength()); 274 DCHECK_LE(instruction->GetVectorLength(), 16u); 275 __ NorV(dst, src, src); // lanes do not matter 276 break; 277 default: 278 LOG(FATAL) << "Unsupported SIMD type"; 279 UNREACHABLE(); 280 } 281 } 282 283 // Helper to set up locations for vector binary operations. 284 static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) { 285 LocationSummary* locations = new (arena) LocationSummary(instruction); 286 switch (instruction->GetPackedType()) { 287 case Primitive::kPrimBoolean: 288 case Primitive::kPrimByte: 289 case Primitive::kPrimChar: 290 case Primitive::kPrimShort: 291 case Primitive::kPrimInt: 292 case Primitive::kPrimLong: 293 case Primitive::kPrimFloat: 294 case Primitive::kPrimDouble: 295 locations->SetInAt(0, Location::RequiresFpuRegister()); 296 locations->SetInAt(1, Location::RequiresFpuRegister()); 297 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 298 break; 299 default: 300 LOG(FATAL) << "Unsupported SIMD type"; 301 UNREACHABLE(); 302 } 303 } 304 305 void LocationsBuilderMIPS64::VisitVecAdd(HVecAdd* instruction) { 306 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 307 } 308 309 void InstructionCodeGeneratorMIPS64::VisitVecAdd(HVecAdd* instruction) { 310 LocationSummary* locations = instruction->GetLocations(); 311 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 312 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 313 VectorRegister dst = VectorRegisterFrom(locations->Out()); 314 switch (instruction->GetPackedType()) { 315 case Primitive::kPrimByte: 316 DCHECK_EQ(16u, instruction->GetVectorLength()); 317 __ AddvB(dst, lhs, rhs); 318 break; 319 case Primitive::kPrimChar: 320 case Primitive::kPrimShort: 321 DCHECK_EQ(8u, instruction->GetVectorLength()); 322 __ AddvH(dst, lhs, rhs); 323 break; 324 case Primitive::kPrimInt: 325 DCHECK_EQ(4u, instruction->GetVectorLength()); 326 __ AddvW(dst, lhs, rhs); 327 break; 328 case Primitive::kPrimLong: 329 DCHECK_EQ(2u, instruction->GetVectorLength()); 330 __ AddvD(dst, lhs, rhs); 331 break; 332 case Primitive::kPrimFloat: 333 DCHECK_EQ(4u, instruction->GetVectorLength()); 334 __ FaddW(dst, lhs, rhs); 335 break; 336 case Primitive::kPrimDouble: 337 DCHECK_EQ(2u, instruction->GetVectorLength()); 338 __ FaddD(dst, lhs, rhs); 339 break; 340 default: 341 LOG(FATAL) << "Unsupported SIMD type"; 342 UNREACHABLE(); 343 } 344 } 345 346 void LocationsBuilderMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) { 347 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 348 } 349 350 void InstructionCodeGeneratorMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) { 351 LocationSummary* locations = instruction->GetLocations(); 352 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 353 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 354 VectorRegister dst = VectorRegisterFrom(locations->Out()); 355 switch (instruction->GetPackedType()) { 356 case Primitive::kPrimByte: 357 DCHECK_EQ(16u, instruction->GetVectorLength()); 358 if (instruction->IsUnsigned()) { 359 instruction->IsRounded() 360 ? __ Aver_uB(dst, lhs, rhs) 361 : __ Ave_uB(dst, lhs, rhs); 362 } else { 363 instruction->IsRounded() 364 ? __ Aver_sB(dst, lhs, rhs) 365 : __ Ave_sB(dst, lhs, rhs); 366 } 367 break; 368 case Primitive::kPrimChar: 369 case Primitive::kPrimShort: 370 DCHECK_EQ(8u, instruction->GetVectorLength()); 371 if (instruction->IsUnsigned()) { 372 instruction->IsRounded() 373 ? __ Aver_uH(dst, lhs, rhs) 374 : __ Ave_uH(dst, lhs, rhs); 375 } else { 376 instruction->IsRounded() 377 ? __ Aver_sH(dst, lhs, rhs) 378 : __ Ave_sH(dst, lhs, rhs); 379 } 380 break; 381 default: 382 LOG(FATAL) << "Unsupported SIMD type"; 383 UNREACHABLE(); 384 } 385 } 386 387 void LocationsBuilderMIPS64::VisitVecSub(HVecSub* instruction) { 388 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 389 } 390 391 void InstructionCodeGeneratorMIPS64::VisitVecSub(HVecSub* instruction) { 392 LocationSummary* locations = instruction->GetLocations(); 393 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 394 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 395 VectorRegister dst = VectorRegisterFrom(locations->Out()); 396 switch (instruction->GetPackedType()) { 397 case Primitive::kPrimByte: 398 DCHECK_EQ(16u, instruction->GetVectorLength()); 399 __ SubvB(dst, lhs, rhs); 400 break; 401 case Primitive::kPrimChar: 402 case Primitive::kPrimShort: 403 DCHECK_EQ(8u, instruction->GetVectorLength()); 404 __ SubvH(dst, lhs, rhs); 405 break; 406 case Primitive::kPrimInt: 407 DCHECK_EQ(4u, instruction->GetVectorLength()); 408 __ SubvW(dst, lhs, rhs); 409 break; 410 case Primitive::kPrimLong: 411 DCHECK_EQ(2u, instruction->GetVectorLength()); 412 __ SubvD(dst, lhs, rhs); 413 break; 414 case Primitive::kPrimFloat: 415 DCHECK_EQ(4u, instruction->GetVectorLength()); 416 __ FsubW(dst, lhs, rhs); 417 break; 418 case Primitive::kPrimDouble: 419 DCHECK_EQ(2u, instruction->GetVectorLength()); 420 __ FsubD(dst, lhs, rhs); 421 break; 422 default: 423 LOG(FATAL) << "Unsupported SIMD type"; 424 UNREACHABLE(); 425 } 426 } 427 428 void LocationsBuilderMIPS64::VisitVecMul(HVecMul* instruction) { 429 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 430 } 431 432 void InstructionCodeGeneratorMIPS64::VisitVecMul(HVecMul* instruction) { 433 LocationSummary* locations = instruction->GetLocations(); 434 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 435 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 436 VectorRegister dst = VectorRegisterFrom(locations->Out()); 437 switch (instruction->GetPackedType()) { 438 case Primitive::kPrimByte: 439 DCHECK_EQ(16u, instruction->GetVectorLength()); 440 __ MulvB(dst, lhs, rhs); 441 break; 442 case Primitive::kPrimChar: 443 case Primitive::kPrimShort: 444 DCHECK_EQ(8u, instruction->GetVectorLength()); 445 __ MulvH(dst, lhs, rhs); 446 break; 447 case Primitive::kPrimInt: 448 DCHECK_EQ(4u, instruction->GetVectorLength()); 449 __ MulvW(dst, lhs, rhs); 450 break; 451 case Primitive::kPrimLong: 452 DCHECK_EQ(2u, instruction->GetVectorLength()); 453 __ MulvD(dst, lhs, rhs); 454 break; 455 case Primitive::kPrimFloat: 456 DCHECK_EQ(4u, instruction->GetVectorLength()); 457 __ FmulW(dst, lhs, rhs); 458 break; 459 case Primitive::kPrimDouble: 460 DCHECK_EQ(2u, instruction->GetVectorLength()); 461 __ FmulD(dst, lhs, rhs); 462 break; 463 default: 464 LOG(FATAL) << "Unsupported SIMD type"; 465 UNREACHABLE(); 466 } 467 } 468 469 void LocationsBuilderMIPS64::VisitVecDiv(HVecDiv* instruction) { 470 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 471 } 472 473 void InstructionCodeGeneratorMIPS64::VisitVecDiv(HVecDiv* instruction) { 474 LocationSummary* locations = instruction->GetLocations(); 475 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 476 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 477 VectorRegister dst = VectorRegisterFrom(locations->Out()); 478 switch (instruction->GetPackedType()) { 479 case Primitive::kPrimFloat: 480 DCHECK_EQ(4u, instruction->GetVectorLength()); 481 __ FdivW(dst, lhs, rhs); 482 break; 483 case Primitive::kPrimDouble: 484 DCHECK_EQ(2u, instruction->GetVectorLength()); 485 __ FdivD(dst, lhs, rhs); 486 break; 487 default: 488 LOG(FATAL) << "Unsupported SIMD type"; 489 UNREACHABLE(); 490 } 491 } 492 493 void LocationsBuilderMIPS64::VisitVecMin(HVecMin* instruction) { 494 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 495 } 496 497 void InstructionCodeGeneratorMIPS64::VisitVecMin(HVecMin* instruction) { 498 LocationSummary* locations = instruction->GetLocations(); 499 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 500 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 501 VectorRegister dst = VectorRegisterFrom(locations->Out()); 502 switch (instruction->GetPackedType()) { 503 case Primitive::kPrimByte: 504 DCHECK_EQ(16u, instruction->GetVectorLength()); 505 if (instruction->IsUnsigned()) { 506 __ Min_uB(dst, lhs, rhs); 507 } else { 508 __ Min_sB(dst, lhs, rhs); 509 } 510 break; 511 case Primitive::kPrimChar: 512 case Primitive::kPrimShort: 513 DCHECK_EQ(8u, instruction->GetVectorLength()); 514 if (instruction->IsUnsigned()) { 515 __ Min_uH(dst, lhs, rhs); 516 } else { 517 __ Min_sH(dst, lhs, rhs); 518 } 519 break; 520 case Primitive::kPrimInt: 521 DCHECK_EQ(4u, instruction->GetVectorLength()); 522 if (instruction->IsUnsigned()) { 523 __ Min_uW(dst, lhs, rhs); 524 } else { 525 __ Min_sW(dst, lhs, rhs); 526 } 527 break; 528 case Primitive::kPrimLong: 529 DCHECK_EQ(2u, instruction->GetVectorLength()); 530 if (instruction->IsUnsigned()) { 531 __ Min_uD(dst, lhs, rhs); 532 } else { 533 __ Min_sD(dst, lhs, rhs); 534 } 535 break; 536 // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value. 537 // TODO: Fix min(x, NaN) cases for float and double. 538 case Primitive::kPrimFloat: 539 DCHECK_EQ(4u, instruction->GetVectorLength()); 540 DCHECK(!instruction->IsUnsigned()); 541 __ FminW(dst, lhs, rhs); 542 break; 543 case Primitive::kPrimDouble: 544 DCHECK_EQ(2u, instruction->GetVectorLength()); 545 DCHECK(!instruction->IsUnsigned()); 546 __ FminD(dst, lhs, rhs); 547 break; 548 default: 549 LOG(FATAL) << "Unsupported SIMD type"; 550 UNREACHABLE(); 551 } 552 } 553 554 void LocationsBuilderMIPS64::VisitVecMax(HVecMax* instruction) { 555 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 556 } 557 558 void InstructionCodeGeneratorMIPS64::VisitVecMax(HVecMax* instruction) { 559 LocationSummary* locations = instruction->GetLocations(); 560 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 561 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 562 VectorRegister dst = VectorRegisterFrom(locations->Out()); 563 switch (instruction->GetPackedType()) { 564 case Primitive::kPrimByte: 565 DCHECK_EQ(16u, instruction->GetVectorLength()); 566 if (instruction->IsUnsigned()) { 567 __ Max_uB(dst, lhs, rhs); 568 } else { 569 __ Max_sB(dst, lhs, rhs); 570 } 571 break; 572 case Primitive::kPrimChar: 573 case Primitive::kPrimShort: 574 DCHECK_EQ(8u, instruction->GetVectorLength()); 575 if (instruction->IsUnsigned()) { 576 __ Max_uH(dst, lhs, rhs); 577 } else { 578 __ Max_sH(dst, lhs, rhs); 579 } 580 break; 581 case Primitive::kPrimInt: 582 DCHECK_EQ(4u, instruction->GetVectorLength()); 583 if (instruction->IsUnsigned()) { 584 __ Max_uW(dst, lhs, rhs); 585 } else { 586 __ Max_sW(dst, lhs, rhs); 587 } 588 break; 589 case Primitive::kPrimLong: 590 DCHECK_EQ(2u, instruction->GetVectorLength()); 591 if (instruction->IsUnsigned()) { 592 __ Max_uD(dst, lhs, rhs); 593 } else { 594 __ Max_sD(dst, lhs, rhs); 595 } 596 break; 597 // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value. 598 // TODO: Fix max(x, NaN) cases for float and double. 599 case Primitive::kPrimFloat: 600 DCHECK_EQ(4u, instruction->GetVectorLength()); 601 DCHECK(!instruction->IsUnsigned()); 602 __ FmaxW(dst, lhs, rhs); 603 break; 604 case Primitive::kPrimDouble: 605 DCHECK_EQ(2u, instruction->GetVectorLength()); 606 DCHECK(!instruction->IsUnsigned()); 607 __ FmaxD(dst, lhs, rhs); 608 break; 609 default: 610 LOG(FATAL) << "Unsupported SIMD type"; 611 UNREACHABLE(); 612 } 613 } 614 615 void LocationsBuilderMIPS64::VisitVecAnd(HVecAnd* instruction) { 616 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 617 } 618 619 void InstructionCodeGeneratorMIPS64::VisitVecAnd(HVecAnd* instruction) { 620 LocationSummary* locations = instruction->GetLocations(); 621 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 622 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 623 VectorRegister dst = VectorRegisterFrom(locations->Out()); 624 switch (instruction->GetPackedType()) { 625 case Primitive::kPrimBoolean: 626 case Primitive::kPrimByte: 627 case Primitive::kPrimChar: 628 case Primitive::kPrimShort: 629 case Primitive::kPrimInt: 630 case Primitive::kPrimLong: 631 case Primitive::kPrimFloat: 632 case Primitive::kPrimDouble: 633 DCHECK_LE(2u, instruction->GetVectorLength()); 634 DCHECK_LE(instruction->GetVectorLength(), 16u); 635 __ AndV(dst, lhs, rhs); // lanes do not matter 636 break; 637 default: 638 LOG(FATAL) << "Unsupported SIMD type"; 639 UNREACHABLE(); 640 } 641 } 642 643 void LocationsBuilderMIPS64::VisitVecAndNot(HVecAndNot* instruction) { 644 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 645 } 646 647 void InstructionCodeGeneratorMIPS64::VisitVecAndNot(HVecAndNot* instruction) { 648 LOG(FATAL) << "No SIMD for " << instruction->GetId(); 649 } 650 651 void LocationsBuilderMIPS64::VisitVecOr(HVecOr* instruction) { 652 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 653 } 654 655 void InstructionCodeGeneratorMIPS64::VisitVecOr(HVecOr* instruction) { 656 LocationSummary* locations = instruction->GetLocations(); 657 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 658 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 659 VectorRegister dst = VectorRegisterFrom(locations->Out()); 660 switch (instruction->GetPackedType()) { 661 case Primitive::kPrimBoolean: 662 case Primitive::kPrimByte: 663 case Primitive::kPrimChar: 664 case Primitive::kPrimShort: 665 case Primitive::kPrimInt: 666 case Primitive::kPrimLong: 667 case Primitive::kPrimFloat: 668 case Primitive::kPrimDouble: 669 DCHECK_LE(2u, instruction->GetVectorLength()); 670 DCHECK_LE(instruction->GetVectorLength(), 16u); 671 __ OrV(dst, lhs, rhs); // lanes do not matter 672 break; 673 default: 674 LOG(FATAL) << "Unsupported SIMD type"; 675 UNREACHABLE(); 676 } 677 } 678 679 void LocationsBuilderMIPS64::VisitVecXor(HVecXor* instruction) { 680 CreateVecBinOpLocations(GetGraph()->GetArena(), instruction); 681 } 682 683 void InstructionCodeGeneratorMIPS64::VisitVecXor(HVecXor* instruction) { 684 LocationSummary* locations = instruction->GetLocations(); 685 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 686 VectorRegister rhs = VectorRegisterFrom(locations->InAt(1)); 687 VectorRegister dst = VectorRegisterFrom(locations->Out()); 688 switch (instruction->GetPackedType()) { 689 case Primitive::kPrimBoolean: 690 case Primitive::kPrimByte: 691 case Primitive::kPrimChar: 692 case Primitive::kPrimShort: 693 case Primitive::kPrimInt: 694 case Primitive::kPrimLong: 695 case Primitive::kPrimFloat: 696 case Primitive::kPrimDouble: 697 DCHECK_LE(2u, instruction->GetVectorLength()); 698 DCHECK_LE(instruction->GetVectorLength(), 16u); 699 __ XorV(dst, lhs, rhs); // lanes do not matter 700 break; 701 default: 702 LOG(FATAL) << "Unsupported SIMD type"; 703 UNREACHABLE(); 704 } 705 } 706 707 // Helper to set up locations for vector shift operations. 708 static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) { 709 LocationSummary* locations = new (arena) LocationSummary(instruction); 710 switch (instruction->GetPackedType()) { 711 case Primitive::kPrimByte: 712 case Primitive::kPrimChar: 713 case Primitive::kPrimShort: 714 case Primitive::kPrimInt: 715 case Primitive::kPrimLong: 716 locations->SetInAt(0, Location::RequiresFpuRegister()); 717 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant())); 718 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 719 break; 720 default: 721 LOG(FATAL) << "Unsupported SIMD type"; 722 UNREACHABLE(); 723 } 724 } 725 726 void LocationsBuilderMIPS64::VisitVecShl(HVecShl* instruction) { 727 CreateVecShiftLocations(GetGraph()->GetArena(), instruction); 728 } 729 730 void InstructionCodeGeneratorMIPS64::VisitVecShl(HVecShl* instruction) { 731 LocationSummary* locations = instruction->GetLocations(); 732 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 733 VectorRegister dst = VectorRegisterFrom(locations->Out()); 734 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 735 switch (instruction->GetPackedType()) { 736 case Primitive::kPrimByte: 737 DCHECK_EQ(16u, instruction->GetVectorLength()); 738 __ SlliB(dst, lhs, value); 739 break; 740 case Primitive::kPrimChar: 741 case Primitive::kPrimShort: 742 DCHECK_EQ(8u, instruction->GetVectorLength()); 743 __ SlliH(dst, lhs, value); 744 break; 745 case Primitive::kPrimInt: 746 DCHECK_EQ(4u, instruction->GetVectorLength()); 747 __ SlliW(dst, lhs, value); 748 break; 749 case Primitive::kPrimLong: 750 DCHECK_EQ(2u, instruction->GetVectorLength()); 751 __ SlliD(dst, lhs, value); 752 break; 753 default: 754 LOG(FATAL) << "Unsupported SIMD type"; 755 UNREACHABLE(); 756 } 757 } 758 759 void LocationsBuilderMIPS64::VisitVecShr(HVecShr* instruction) { 760 CreateVecShiftLocations(GetGraph()->GetArena(), instruction); 761 } 762 763 void InstructionCodeGeneratorMIPS64::VisitVecShr(HVecShr* instruction) { 764 LocationSummary* locations = instruction->GetLocations(); 765 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 766 VectorRegister dst = VectorRegisterFrom(locations->Out()); 767 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 768 switch (instruction->GetPackedType()) { 769 case Primitive::kPrimByte: 770 DCHECK_EQ(16u, instruction->GetVectorLength()); 771 __ SraiB(dst, lhs, value); 772 break; 773 case Primitive::kPrimChar: 774 case Primitive::kPrimShort: 775 DCHECK_EQ(8u, instruction->GetVectorLength()); 776 __ SraiH(dst, lhs, value); 777 break; 778 case Primitive::kPrimInt: 779 DCHECK_EQ(4u, instruction->GetVectorLength()); 780 __ SraiW(dst, lhs, value); 781 break; 782 case Primitive::kPrimLong: 783 DCHECK_EQ(2u, instruction->GetVectorLength()); 784 __ SraiD(dst, lhs, value); 785 break; 786 default: 787 LOG(FATAL) << "Unsupported SIMD type"; 788 UNREACHABLE(); 789 } 790 } 791 792 void LocationsBuilderMIPS64::VisitVecUShr(HVecUShr* instruction) { 793 CreateVecShiftLocations(GetGraph()->GetArena(), instruction); 794 } 795 796 void InstructionCodeGeneratorMIPS64::VisitVecUShr(HVecUShr* instruction) { 797 LocationSummary* locations = instruction->GetLocations(); 798 VectorRegister lhs = VectorRegisterFrom(locations->InAt(0)); 799 VectorRegister dst = VectorRegisterFrom(locations->Out()); 800 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 801 switch (instruction->GetPackedType()) { 802 case Primitive::kPrimByte: 803 DCHECK_EQ(16u, instruction->GetVectorLength()); 804 __ SrliB(dst, lhs, value); 805 break; 806 case Primitive::kPrimChar: 807 case Primitive::kPrimShort: 808 DCHECK_EQ(8u, instruction->GetVectorLength()); 809 __ SrliH(dst, lhs, value); 810 break; 811 case Primitive::kPrimInt: 812 DCHECK_EQ(4u, instruction->GetVectorLength()); 813 __ SrliW(dst, lhs, value); 814 break; 815 case Primitive::kPrimLong: 816 DCHECK_EQ(2u, instruction->GetVectorLength()); 817 __ SrliD(dst, lhs, value); 818 break; 819 default: 820 LOG(FATAL) << "Unsupported SIMD type"; 821 UNREACHABLE(); 822 } 823 } 824 825 void LocationsBuilderMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) { 826 LOG(FATAL) << "No SIMD for " << instr->GetId(); 827 } 828 829 void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) { 830 LOG(FATAL) << "No SIMD for " << instr->GetId(); 831 } 832 833 // Helper to set up locations for vector memory operations. 834 static void CreateVecMemLocations(ArenaAllocator* arena, 835 HVecMemoryOperation* instruction, 836 bool is_load) { 837 LocationSummary* locations = new (arena) LocationSummary(instruction); 838 switch (instruction->GetPackedType()) { 839 case Primitive::kPrimBoolean: 840 case Primitive::kPrimByte: 841 case Primitive::kPrimChar: 842 case Primitive::kPrimShort: 843 case Primitive::kPrimInt: 844 case Primitive::kPrimLong: 845 case Primitive::kPrimFloat: 846 case Primitive::kPrimDouble: 847 locations->SetInAt(0, Location::RequiresRegister()); 848 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 849 if (is_load) { 850 locations->SetOut(Location::RequiresFpuRegister()); 851 } else { 852 locations->SetInAt(2, Location::RequiresFpuRegister()); 853 } 854 break; 855 default: 856 LOG(FATAL) << "Unsupported SIMD type"; 857 UNREACHABLE(); 858 } 859 } 860 861 // Helper to prepare register and offset for vector memory operations. Returns the offset and sets 862 // the output parameter adjusted_base to the original base or to a reserved temporary register (AT). 863 int32_t InstructionCodeGeneratorMIPS64::VecAddress(LocationSummary* locations, 864 size_t size, 865 /* out */ GpuRegister* adjusted_base) { 866 GpuRegister base = locations->InAt(0).AsRegister<GpuRegister>(); 867 Location index = locations->InAt(1); 868 int scale = TIMES_1; 869 switch (size) { 870 case 2: scale = TIMES_2; break; 871 case 4: scale = TIMES_4; break; 872 case 8: scale = TIMES_8; break; 873 default: break; 874 } 875 int32_t offset = mirror::Array::DataOffset(size).Int32Value(); 876 877 if (index.IsConstant()) { 878 offset += index.GetConstant()->AsIntConstant()->GetValue() << scale; 879 __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale); 880 *adjusted_base = base; 881 } else { 882 GpuRegister index_reg = index.AsRegister<GpuRegister>(); 883 if (scale != TIMES_1) { 884 __ Dlsa(AT, index_reg, base, scale); 885 } else { 886 __ Daddu(AT, base, index_reg); 887 } 888 *adjusted_base = AT; 889 } 890 return offset; 891 } 892 893 void LocationsBuilderMIPS64::VisitVecLoad(HVecLoad* instruction) { 894 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ true); 895 } 896 897 void InstructionCodeGeneratorMIPS64::VisitVecLoad(HVecLoad* instruction) { 898 LocationSummary* locations = instruction->GetLocations(); 899 size_t size = Primitive::ComponentSize(instruction->GetPackedType()); 900 VectorRegister reg = VectorRegisterFrom(locations->Out()); 901 GpuRegister base; 902 int32_t offset = VecAddress(locations, size, &base); 903 switch (instruction->GetPackedType()) { 904 case Primitive::kPrimBoolean: 905 case Primitive::kPrimByte: 906 DCHECK_EQ(16u, instruction->GetVectorLength()); 907 __ LdB(reg, base, offset); 908 break; 909 case Primitive::kPrimChar: 910 case Primitive::kPrimShort: 911 // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned 912 // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned 913 // loads and stores. 914 // TODO: Implement support for StringCharAt. 915 DCHECK(!instruction->IsStringCharAt()); 916 DCHECK_EQ(8u, instruction->GetVectorLength()); 917 __ LdH(reg, base, offset); 918 break; 919 case Primitive::kPrimInt: 920 case Primitive::kPrimFloat: 921 DCHECK_EQ(4u, instruction->GetVectorLength()); 922 __ LdW(reg, base, offset); 923 break; 924 case Primitive::kPrimLong: 925 case Primitive::kPrimDouble: 926 DCHECK_EQ(2u, instruction->GetVectorLength()); 927 __ LdD(reg, base, offset); 928 break; 929 default: 930 LOG(FATAL) << "Unsupported SIMD type"; 931 UNREACHABLE(); 932 } 933 } 934 935 void LocationsBuilderMIPS64::VisitVecStore(HVecStore* instruction) { 936 CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ false); 937 } 938 939 void InstructionCodeGeneratorMIPS64::VisitVecStore(HVecStore* instruction) { 940 LocationSummary* locations = instruction->GetLocations(); 941 size_t size = Primitive::ComponentSize(instruction->GetPackedType()); 942 VectorRegister reg = VectorRegisterFrom(locations->InAt(2)); 943 GpuRegister base; 944 int32_t offset = VecAddress(locations, size, &base); 945 switch (instruction->GetPackedType()) { 946 case Primitive::kPrimBoolean: 947 case Primitive::kPrimByte: 948 DCHECK_EQ(16u, instruction->GetVectorLength()); 949 __ StB(reg, base, offset); 950 break; 951 case Primitive::kPrimChar: 952 case Primitive::kPrimShort: 953 DCHECK_EQ(8u, instruction->GetVectorLength()); 954 __ StH(reg, base, offset); 955 break; 956 case Primitive::kPrimInt: 957 case Primitive::kPrimFloat: 958 DCHECK_EQ(4u, instruction->GetVectorLength()); 959 __ StW(reg, base, offset); 960 break; 961 case Primitive::kPrimLong: 962 case Primitive::kPrimDouble: 963 DCHECK_EQ(2u, instruction->GetVectorLength()); 964 __ StD(reg, base, offset); 965 break; 966 default: 967 LOG(FATAL) << "Unsupported SIMD type"; 968 UNREACHABLE(); 969 } 970 } 971 972 #undef __ 973 974 } // namespace mips64 975 } // namespace art 976