summaryrefslogtreecommitdiff
path: root/compiler/optimizing/code_generator_vector_mips.cc
diff options
context:
space:
mode:
authorLena Djokic <Lena.Djokic@imgtec.com>2017-06-22 13:49:59 +0200
committerLena Djokic <Lena.Djokic@imgtec.com>2017-07-13 10:34:27 +0200
commit51765b098301fff1897361b2d1a21af356d9d6d8 (patch)
tree5d35468c9ecd428803fe7e4339fb8e251b6ed926 /compiler/optimizing/code_generator_vector_mips.cc
parente63a91111d13f33028c2988ded53a4659140ca2e (diff)
MIPS32: ART Vectorizer
MIPS32 implementation which uses MSA extension. Note: Testing is done with checker parts of tests 640, 645, 646 and 651, locally changed to cover MIPS32 cases. These changes can't be included in this patch since MSA is not a default option. Test: ./testrunner.py --target --optimizing -j1 in QEMU (mips32r6) Change-Id: Ieba28f94c48c943d5444017bede9a5d409149762
Diffstat (limited to 'compiler/optimizing/code_generator_vector_mips.cc')
-rw-r--r--compiler/optimizing/code_generator_vector_mips.cc748
1 files changed, 722 insertions, 26 deletions
diff --git a/compiler/optimizing/code_generator_vector_mips.cc b/compiler/optimizing/code_generator_vector_mips.cc
index c4a32252d9..ea36e90112 100644
--- a/compiler/optimizing/code_generator_vector_mips.cc
+++ b/compiler/optimizing/code_generator_vector_mips.cc
@@ -15,6 +15,7 @@
*/
#include "code_generator_mips.h"
+#include "mirror/array-inl.h"
namespace art {
namespace mips {
@@ -23,11 +24,68 @@ namespace mips {
#define __ down_cast<MipsAssembler*>(GetAssembler())-> // NOLINT
void LocationsBuilderMIPS::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void InstructionCodeGeneratorMIPS::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ FillB(dst, locations->InAt(0).AsRegister<Register>());
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ FillH(dst, locations->InAt(0).AsRegister<Register>());
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, locations->InAt(0).AsRegister<Register>());
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ Mtc1(locations->InAt(0).AsRegisterPairLow<Register>(), FTMP);
+ __ MoveToFpuHigh(locations->InAt(0).AsRegisterPairHigh<Register>(), FTMP);
+ __ ReplicateFPToVectorRegister(dst, FTMP, /* is_double */ true);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ ReplicateFPToVectorRegister(dst,
+ locations->InAt(0).AsFpuRegister<FRegister>(),
+ /* is_double */ false);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ ReplicateFPToVectorRegister(dst,
+ locations->InAt(0).AsFpuRegister<FRegister>(),
+ /* is_double */ true);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecSetScalars(HVecSetScalars* instruction) {
@@ -51,13 +109,23 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(),
+ instruction->IsVecNot() ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap);
+ break;
case Primitive::kPrimByte:
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- DCHECK(locations);
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(),
+ (instruction->IsVecNeg() || instruction->IsVecAbs())
+ ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -70,7 +138,17 @@ void LocationsBuilderMIPS::VisitVecCnv(HVecCnv* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecCnv(HVecCnv* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ Primitive::Type from = instruction->GetInputType();
+ Primitive::Type to = instruction->GetResultType();
+ if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Ffint_sW(dst, src);
+ } else {
+ LOG(FATAL) << "Unsupported SIMD type";
+ }
}
void LocationsBuilderMIPS::VisitVecNeg(HVecNeg* instruction) {
@@ -78,7 +156,45 @@ void LocationsBuilderMIPS::VisitVecNeg(HVecNeg* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecNeg(HVecNeg* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ FillB(dst, ZERO);
+ __ SubvB(dst, dst, src);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ FillH(dst, ZERO);
+ __ SubvH(dst, dst, src);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO);
+ __ SubvW(dst, dst, src);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO);
+ __ SubvD(dst, dst, src);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO);
+ __ FsubW(dst, dst, src);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO);
+ __ FsubD(dst, dst, src);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecAbs(HVecAbs* instruction) {
@@ -86,7 +202,47 @@ void LocationsBuilderMIPS::VisitVecAbs(HVecAbs* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecAbs(HVecAbs* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ FillB(dst, ZERO); // all zeroes
+ __ Add_aB(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ FillH(dst, ZERO); // all zeroes
+ __ Add_aH(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO); // all zeroes
+ __ Add_aW(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO); // all zeroes
+ __ Add_aD(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ LdiW(dst, -1); // all ones
+ __ SrliW(dst, dst, 1);
+ __ AndV(dst, dst, src);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ LdiD(dst, -1); // all ones
+ __ SrliD(dst, dst, 1);
+ __ AndV(dst, dst, src);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecNot(HVecNot* instruction) {
@@ -94,7 +250,30 @@ void LocationsBuilderMIPS::VisitVecNot(HVecNot* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecNot(HVecNot* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean: // special case boolean-not
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ LdiB(dst, 1);
+ __ XorV(dst, dst, src);
+ break;
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ NorV(dst, src, src); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
// Helper to set up locations for vector binary operations.
@@ -106,9 +285,12 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- DCHECK(locations);
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -121,7 +303,40 @@ void LocationsBuilderMIPS::VisitVecAdd(HVecAdd* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecAdd(HVecAdd* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ AddvB(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ AddvH(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ AddvW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ AddvD(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FaddW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FaddD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
@@ -129,7 +344,40 @@ void LocationsBuilderMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ instruction->IsRounded()
+ ? __ Aver_uB(dst, lhs, rhs)
+ : __ Ave_uB(dst, lhs, rhs);
+ } else {
+ instruction->IsRounded()
+ ? __ Aver_sB(dst, lhs, rhs)
+ : __ Ave_sB(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ instruction->IsRounded()
+ ? __ Aver_uH(dst, lhs, rhs)
+ : __ Ave_uH(dst, lhs, rhs);
+ } else {
+ instruction->IsRounded()
+ ? __ Aver_sH(dst, lhs, rhs)
+ : __ Ave_sH(dst, lhs, rhs);
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecSub(HVecSub* instruction) {
@@ -137,7 +385,40 @@ void LocationsBuilderMIPS::VisitVecSub(HVecSub* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecSub(HVecSub* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SubvB(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SubvH(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SubvW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SubvD(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FsubW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FsubD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecMul(HVecMul* instruction) {
@@ -145,7 +426,40 @@ void LocationsBuilderMIPS::VisitVecMul(HVecMul* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecMul(HVecMul* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ MulvB(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ MulvH(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ MulvW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ MulvD(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FmulW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FmulD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecDiv(HVecDiv* instruction) {
@@ -153,7 +467,23 @@ void LocationsBuilderMIPS::VisitVecDiv(HVecDiv* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecDiv(HVecDiv* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FdivW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FdivD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecMin(HVecMin* instruction) {
@@ -161,7 +491,60 @@ void LocationsBuilderMIPS::VisitVecMin(HVecMin* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecMin(HVecMin* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Min_uB(dst, lhs, rhs);
+ } else {
+ __ Min_sB(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Min_uH(dst, lhs, rhs);
+ } else {
+ __ Min_sH(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Min_uW(dst, lhs, rhs);
+ } else {
+ __ Min_sW(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Min_uD(dst, lhs, rhs);
+ } else {
+ __ Min_sD(dst, lhs, rhs);
+ }
+ break;
+ // When one of arguments is NaN, fmin.df returns other argument, but Java expects a NaN value.
+ // TODO: Fix min(x, NaN) cases for float and double.
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ DCHECK(!instruction->IsUnsigned());
+ __ FminW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ DCHECK(!instruction->IsUnsigned());
+ __ FminD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecMax(HVecMax* instruction) {
@@ -169,7 +552,60 @@ void LocationsBuilderMIPS::VisitVecMax(HVecMax* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecMax(HVecMax* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Max_uB(dst, lhs, rhs);
+ } else {
+ __ Max_sB(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Max_uH(dst, lhs, rhs);
+ } else {
+ __ Max_sH(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Max_uW(dst, lhs, rhs);
+ } else {
+ __ Max_sW(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ __ Max_uD(dst, lhs, rhs);
+ } else {
+ __ Max_sD(dst, lhs, rhs);
+ }
+ break;
+ // When one of arguments is NaN, fmax.df returns other argument, but Java expects a NaN value.
+ // TODO: Fix max(x, NaN) cases for float and double.
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ DCHECK(!instruction->IsUnsigned());
+ __ FmaxW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ DCHECK(!instruction->IsUnsigned());
+ __ FmaxD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecAnd(HVecAnd* instruction) {
@@ -177,7 +613,27 @@ void LocationsBuilderMIPS::VisitVecAnd(HVecAnd* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecAnd(HVecAnd* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ AndV(dst, lhs, rhs); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecAndNot(HVecAndNot* instruction) {
@@ -193,7 +649,27 @@ void LocationsBuilderMIPS::VisitVecOr(HVecOr* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecOr(HVecOr* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ OrV(dst, lhs, rhs); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecXor(HVecXor* instruction) {
@@ -201,7 +677,27 @@ void LocationsBuilderMIPS::VisitVecXor(HVecXor* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecXor(HVecXor* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ XorV(dst, lhs, rhs); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
// Helper to set up locations for vector shift operations.
@@ -213,7 +709,9 @@ static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation*
case Primitive::kPrimShort:
case Primitive::kPrimInt:
case Primitive::kPrimLong:
- DCHECK(locations);
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -226,7 +724,32 @@ void LocationsBuilderMIPS::VisitVecShl(HVecShl* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecShl(HVecShl* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SlliB(dst, lhs, value);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SlliH(dst, lhs, value);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SlliW(dst, lhs, value);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SlliD(dst, lhs, value);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecShr(HVecShr* instruction) {
@@ -234,7 +757,32 @@ void LocationsBuilderMIPS::VisitVecShr(HVecShr* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecShr(HVecShr* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SraiB(dst, lhs, value);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SraiH(dst, lhs, value);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SraiW(dst, lhs, value);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SraiD(dst, lhs, value);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecUShr(HVecUShr* instruction) {
@@ -242,7 +790,32 @@ void LocationsBuilderMIPS::VisitVecUShr(HVecUShr* instruction) {
}
void InstructionCodeGeneratorMIPS::VisitVecUShr(HVecUShr* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SrliB(dst, lhs, value);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SrliH(dst, lhs, value);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SrliW(dst, lhs, value);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SrliD(dst, lhs, value);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
@@ -253,20 +826,143 @@ void InstructionCodeGeneratorMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumu
LOG(FATAL) << "No SIMD for " << instr->GetId();
}
+// Helper to set up locations for vector memory operations.
+static void CreateVecMemLocations(ArenaAllocator* arena,
+ HVecMemoryOperation* instruction,
+ bool is_load) {
+ LocationSummary* locations = new (arena) LocationSummary(instruction);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ if (is_load) {
+ locations->SetOut(Location::RequiresFpuRegister());
+ } else {
+ locations->SetInAt(2, Location::RequiresFpuRegister());
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+}
+
+// Helper to prepare register and offset for vector memory operations. Returns the offset and sets
+// the output parameter adjusted_base to the original base or to a reserved temporary register (AT).
+int32_t InstructionCodeGeneratorMIPS::VecAddress(LocationSummary* locations,
+ size_t size,
+ /* out */ Register* adjusted_base) {
+ Register base = locations->InAt(0).AsRegister<Register>();
+ Location index = locations->InAt(1);
+ int scale = TIMES_1;
+ switch (size) {
+ case 2: scale = TIMES_2; break;
+ case 4: scale = TIMES_4; break;
+ case 8: scale = TIMES_8; break;
+ default: break;
+ }
+ int32_t offset = mirror::Array::DataOffset(size).Int32Value();
+
+ if (index.IsConstant()) {
+ offset += index.GetConstant()->AsIntConstant()->GetValue() << scale;
+ __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale);
+ *adjusted_base = base;
+ } else {
+ Register index_reg = index.AsRegister<Register>();
+ if (scale != TIMES_1) {
+ __ Lsa(AT, index_reg, base, scale);
+ } else {
+ __ Addu(AT, base, index_reg);
+ }
+ *adjusted_base = AT;
+ }
+ return offset;
+}
+
void LocationsBuilderMIPS::VisitVecLoad(HVecLoad* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ true);
}
void InstructionCodeGeneratorMIPS::VisitVecLoad(HVecLoad* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+ VectorRegister reg = VectorRegisterFrom(locations->Out());
+ Register base;
+ int32_t offset = VecAddress(locations, size, &base);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ LdB(reg, base, offset);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
+ // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
+ // loads and stores.
+ // TODO: Implement support for StringCharAt.
+ DCHECK(!instruction->IsStringCharAt());
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ LdH(reg, base, offset);
+ break;
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ LdW(reg, base, offset);
+ break;
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ LdD(reg, base, offset);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS::VisitVecStore(HVecStore* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ false);
}
void InstructionCodeGeneratorMIPS::VisitVecStore(HVecStore* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+ VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
+ Register base;
+ int32_t offset = VecAddress(locations, size, &base);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ StB(reg, base, offset);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ StH(reg, base, offset);
+ break;
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ StW(reg, base, offset);
+ break;
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ StD(reg, base, offset);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
#undef __