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