Revert "Revert "Introduce a number of MSA instructions for MIPS64""
This reverts commit 219bf253e5158c4f3438e70864b8bf7235c1e193.
Fixed memory leak in assembler_mips64_test.cc.
Test: mma valgrind-test-art-host-gtest-assembler_mips64_test64
Change-Id: I238833fd4555623c2716432fc67eab7696f1e28e
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 5c48759..d265a44 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -42,7 +42,10 @@
kUseQuaternaryName,
};
-template<typename Ass, typename Reg, typename FPReg, typename Imm>
+// For use in the template as the default type to get a nonvector registers version.
+struct NoVectorRegs {};
+
+template<typename Ass, typename Reg, typename FPReg, typename Imm, typename VecReg = NoVectorRegs>
class AssemblerTest : public testing::Test {
public:
Ass* GetAssembler() {
@@ -146,7 +149,8 @@
std::string (AssemblerTest::*GetName1)(const Reg1&),
std::string (AssemblerTest::*GetName2)(const Reg2&),
const std::string& fmt,
- int bias = 0) {
+ int bias = 0,
+ int multiplier = 1) {
std::string str;
std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0));
@@ -154,7 +158,7 @@
for (auto reg2 : reg2_registers) {
for (int64_t imm : imms) {
ImmType new_imm = CreateImmediate(imm);
- (assembler_.get()->*f)(*reg1, *reg2, new_imm + bias);
+ (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
std::string base = fmt;
std::string reg1_string = (this->*GetName1)(*reg1);
@@ -172,7 +176,7 @@
size_t imm_index = base.find(IMM_TOKEN);
if (imm_index != std::string::npos) {
std::ostringstream sreg;
- sreg << imm + bias;
+ sreg << imm * multiplier + bias;
std::string imm_string = sreg.str();
base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
}
@@ -538,6 +542,69 @@
return str;
}
+ std::string RepeatVV(void (Ass::*f)(VecReg, VecReg), const std::string& fmt) {
+ return RepeatTemplatedRegisters<VecReg, VecReg>(f,
+ GetVectorRegisters(),
+ GetVectorRegisters(),
+ &AssemblerTest::GetVecRegName,
+ &AssemblerTest::GetVecRegName,
+ fmt);
+ }
+
+ std::string RepeatVVV(void (Ass::*f)(VecReg, VecReg, VecReg), const std::string& fmt) {
+ return RepeatTemplatedRegisters<VecReg, VecReg, VecReg>(f,
+ GetVectorRegisters(),
+ GetVectorRegisters(),
+ GetVectorRegisters(),
+ &AssemblerTest::GetVecRegName,
+ &AssemblerTest::GetVecRegName,
+ &AssemblerTest::GetVecRegName,
+ fmt);
+ }
+
+ std::string RepeatVR(void (Ass::*f)(VecReg, Reg), const std::string& fmt) {
+ return RepeatTemplatedRegisters<VecReg, Reg>(
+ f,
+ GetVectorRegisters(),
+ GetRegisters(),
+ &AssemblerTest::GetVecRegName,
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ fmt);
+ }
+
+ template <typename ImmType>
+ std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
+ int imm_bits,
+ const std::string& fmt,
+ int bias = 0,
+ int multiplier = 1) {
+ return RepeatTemplatedRegistersImmBits<VecReg, Reg, ImmType>(
+ f,
+ imm_bits,
+ GetVectorRegisters(),
+ GetRegisters(),
+ &AssemblerTest::GetVecRegName,
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ fmt,
+ bias,
+ multiplier);
+ }
+
+ template <typename ImmType>
+ std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
+ int imm_bits,
+ const std::string& fmt,
+ int bias = 0) {
+ return RepeatTemplatedRegistersImmBits<VecReg, VecReg, ImmType>(f,
+ imm_bits,
+ GetVectorRegisters(),
+ GetVectorRegisters(),
+ &AssemblerTest::GetVecRegName,
+ &AssemblerTest::GetVecRegName,
+ fmt,
+ bias);
+ }
+
// This is intended to be run as a test.
bool CheckTools() {
return test_helper_->CheckTools();
@@ -552,6 +619,11 @@
UNREACHABLE();
}
+ virtual std::vector<VecReg*> GetVectorRegisters() {
+ UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
+ UNREACHABLE();
+ }
+
// Secondary register names are the secondary view on registers, e.g., 32b on 64b systems.
virtual std::string GetSecondaryRegisterName(const Reg& reg ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL) << "Architecture does not support secondary registers";
@@ -971,6 +1043,12 @@
return sreg.str();
}
+ std::string GetVecRegName(const VecReg& reg) {
+ std::ostringstream sreg;
+ sreg << reg;
+ return sreg.str();
+ }
+
// If the assembly file needs a header, return it in a sub-class.
virtual const char* GetAssemblyHeader() {
return nullptr;
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 39eb589..c14315a 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -184,6 +184,106 @@
Emit(encoding);
}
+void Mips64Assembler::EmitMsa3R(int operation,
+ int df,
+ VectorRegister wt,
+ VectorRegister ws,
+ VectorRegister wd,
+ int minor_opcode) {
+ CHECK_NE(wt, kNoVectorRegister);
+ CHECK_NE(ws, kNoVectorRegister);
+ CHECK_NE(wd, kNoVectorRegister);
+ uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
+ operation << kMsaOperationShift |
+ df << kDfShift |
+ static_cast<uint32_t>(wt) << kWtShift |
+ static_cast<uint32_t>(ws) << kWsShift |
+ static_cast<uint32_t>(wd) << kWdShift |
+ minor_opcode;
+ Emit(encoding);
+}
+
+void Mips64Assembler::EmitMsaBIT(int operation,
+ int df_m,
+ VectorRegister ws,
+ VectorRegister wd,
+ int minor_opcode) {
+ CHECK_NE(ws, kNoVectorRegister);
+ CHECK_NE(wd, kNoVectorRegister);
+ uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
+ operation << kMsaOperationShift |
+ df_m << kDfMShift |
+ static_cast<uint32_t>(ws) << kWsShift |
+ static_cast<uint32_t>(wd) << kWdShift |
+ minor_opcode;
+ Emit(encoding);
+}
+
+void Mips64Assembler::EmitMsaELM(int operation,
+ int df_n,
+ VectorRegister ws,
+ VectorRegister wd,
+ int minor_opcode) {
+ CHECK_NE(ws, kNoVectorRegister);
+ CHECK_NE(wd, kNoVectorRegister);
+ uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
+ operation << kMsaELMOperationShift |
+ df_n << kDfNShift |
+ static_cast<uint32_t>(ws) << kWsShift |
+ static_cast<uint32_t>(wd) << kWdShift |
+ minor_opcode;
+ Emit(encoding);
+}
+
+void Mips64Assembler::EmitMsaMI10(int s10,
+ GpuRegister rs,
+ VectorRegister wd,
+ int minor_opcode,
+ int df) {
+ CHECK_NE(rs, kNoGpuRegister);
+ CHECK_NE(wd, kNoVectorRegister);
+ CHECK(IsUint<10>(s10)) << s10;
+ uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
+ s10 << kS10Shift |
+ static_cast<uint32_t>(rs) << kWsShift |
+ static_cast<uint32_t>(wd) << kWdShift |
+ minor_opcode << kS10MinorShift |
+ df;
+ Emit(encoding);
+}
+
+void Mips64Assembler::EmitMsa2R(int operation,
+ int df,
+ VectorRegister ws,
+ VectorRegister wd,
+ int minor_opcode) {
+ CHECK_NE(ws, kNoVectorRegister);
+ CHECK_NE(wd, kNoVectorRegister);
+ uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
+ operation << kMsa2ROperationShift |
+ df << kDf2RShift |
+ static_cast<uint32_t>(ws) << kWsShift |
+ static_cast<uint32_t>(wd) << kWdShift |
+ minor_opcode;
+ Emit(encoding);
+}
+
+void Mips64Assembler::EmitMsa2RF(int operation,
+ int df,
+ VectorRegister ws,
+ VectorRegister wd,
+ int minor_opcode) {
+ CHECK_NE(ws, kNoVectorRegister);
+ CHECK_NE(wd, kNoVectorRegister);
+ uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
+ operation << kMsa2RFOperationShift |
+ df << kDf2RShift |
+ static_cast<uint32_t>(ws) << kWsShift |
+ static_cast<uint32_t>(wd) << kWdShift |
+ minor_opcode;
+ Emit(encoding);
+}
+
void Mips64Assembler::Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
EmitR(0, rs, rt, rd, 0, 0x21);
}
@@ -1080,6 +1180,378 @@
Nor(rd, rs, ZERO);
}
+// TODO: Check for MSA presence in Mips64InstructionSetFeatures for each MSA instruction.
+
+void Mips64Assembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12);
+}
+
+void Mips64Assembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
+ EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
+ EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
+ EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
+ EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e);
+}
+
+void Mips64Assembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd);
+}
+
+void Mips64Assembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
+ CHECK(IsUint<3>(shamt3)) << shamt3;
+ EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
+ CHECK(IsUint<4>(shamt4)) << shamt4;
+ EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
+ CHECK(IsUint<5>(shamt5)) << shamt5;
+ EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
+ CHECK(IsUint<6>(shamt6)) << shamt6;
+ EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
+ CHECK(IsUint<3>(shamt3)) << shamt3;
+ EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
+ CHECK(IsUint<4>(shamt4)) << shamt4;
+ EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
+ CHECK(IsUint<5>(shamt5)) << shamt5;
+ EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
+ CHECK(IsUint<6>(shamt6)) << shamt6;
+ EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
+ CHECK(IsUint<3>(shamt3)) << shamt3;
+ EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
+ CHECK(IsUint<4>(shamt4)) << shamt4;
+ EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
+ CHECK(IsUint<5>(shamt5)) << shamt5;
+ EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
+ CHECK(IsUint<6>(shamt6)) << shamt6;
+ EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9);
+}
+
+void Mips64Assembler::MoveV(VectorRegister wd, VectorRegister ws) {
+ EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19);
+}
+
+void Mips64Assembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
+ CHECK(IsUint<4>(n4)) << n4;
+ EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19);
+}
+
+void Mips64Assembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
+ CHECK(IsUint<3>(n3)) << n3;
+ EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19);
+}
+
+void Mips64Assembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
+ CHECK(IsUint<2>(n2)) << n2;
+ EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19);
+}
+
+void Mips64Assembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
+ CHECK(IsUint<1>(n1)) << n1;
+ EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19);
+}
+
+void Mips64Assembler::FillB(VectorRegister wd, GpuRegister rs) {
+ EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e);
+}
+
+void Mips64Assembler::FillH(VectorRegister wd, GpuRegister rs) {
+ EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e);
+}
+
+void Mips64Assembler::FillW(VectorRegister wd, GpuRegister rs) {
+ EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e);
+}
+
+void Mips64Assembler::FillD(VectorRegister wd, GpuRegister rs) {
+ EmitMsa2R(0xc0, 0x3, static_cast<VectorRegister>(rs), wd, 0x1e);
+}
+
+void Mips64Assembler::LdB(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<10>(offset)) << offset;
+ EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0);
+}
+
+void Mips64Assembler::LdH(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<11>(offset)) << offset;
+ CHECK_ALIGNED(offset, kMips64HalfwordSize);
+ EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1);
+}
+
+void Mips64Assembler::LdW(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<12>(offset)) << offset;
+ CHECK_ALIGNED(offset, kMips64WordSize);
+ EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2);
+}
+
+void Mips64Assembler::LdD(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<13>(offset)) << offset;
+ CHECK_ALIGNED(offset, kMips64DoublewordSize);
+ EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3);
+}
+
+void Mips64Assembler::StB(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<10>(offset)) << offset;
+ EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0);
+}
+
+void Mips64Assembler::StH(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<11>(offset)) << offset;
+ CHECK_ALIGNED(offset, kMips64HalfwordSize);
+ EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1);
+}
+
+void Mips64Assembler::StW(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<12>(offset)) << offset;
+ CHECK_ALIGNED(offset, kMips64WordSize);
+ EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2);
+}
+
+void Mips64Assembler::StD(VectorRegister wd, GpuRegister rs, int offset) {
+ CHECK(IsInt<13>(offset)) << offset;
+ CHECK_ALIGNED(offset, kMips64DoublewordSize);
+ EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3);
+}
+
void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
TemplateLoadConst32(this, rd, value);
}
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index b98db65..471fdf2 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -266,6 +266,7 @@
}
}
+static constexpr size_t kMips64HalfwordSize = 2;
static constexpr size_t kMips64WordSize = 4;
static constexpr size_t kMips64DoublewordSize = 8;
@@ -644,6 +645,101 @@
void Clear(GpuRegister rd);
void Not(GpuRegister rd, GpuRegister rs);
+ // MSA instructions.
+ void AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+
+ void AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+
+ void FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+
+ void Ffint_sW(VectorRegister wd, VectorRegister ws);
+ void Ffint_sD(VectorRegister wd, VectorRegister ws);
+ void Ftint_sW(VectorRegister wd, VectorRegister ws);
+ void Ftint_sD(VectorRegister wd, VectorRegister ws);
+
+ void SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+
+ // Immediate shift instructions, where shamtN denotes shift amount (must be between 0 and 2^N-1).
+ void SlliB(VectorRegister wd, VectorRegister ws, int shamt3);
+ void SlliH(VectorRegister wd, VectorRegister ws, int shamt4);
+ void SlliW(VectorRegister wd, VectorRegister ws, int shamt5);
+ void SlliD(VectorRegister wd, VectorRegister ws, int shamt6);
+ void SraiB(VectorRegister wd, VectorRegister ws, int shamt3);
+ void SraiH(VectorRegister wd, VectorRegister ws, int shamt4);
+ void SraiW(VectorRegister wd, VectorRegister ws, int shamt5);
+ void SraiD(VectorRegister wd, VectorRegister ws, int shamt6);
+ void SrliB(VectorRegister wd, VectorRegister ws, int shamt3);
+ void SrliH(VectorRegister wd, VectorRegister ws, int shamt4);
+ void SrliW(VectorRegister wd, VectorRegister ws, int shamt5);
+ void SrliD(VectorRegister wd, VectorRegister ws, int shamt6);
+
+ void MoveV(VectorRegister wd, VectorRegister ws);
+ void SplatiB(VectorRegister wd, VectorRegister ws, int n4);
+ void SplatiH(VectorRegister wd, VectorRegister ws, int n3);
+ void SplatiW(VectorRegister wd, VectorRegister ws, int n2);
+ void SplatiD(VectorRegister wd, VectorRegister ws, int n1);
+ void FillB(VectorRegister wd, GpuRegister rs);
+ void FillH(VectorRegister wd, GpuRegister rs);
+ void FillW(VectorRegister wd, GpuRegister rs);
+ void FillD(VectorRegister wd, GpuRegister rs);
+
+ void LdB(VectorRegister wd, GpuRegister rs, int offset);
+ void LdH(VectorRegister wd, GpuRegister rs, int offset);
+ void LdW(VectorRegister wd, GpuRegister rs, int offset);
+ void LdD(VectorRegister wd, GpuRegister rs, int offset);
+ void StB(VectorRegister wd, GpuRegister rs, int offset);
+ void StH(VectorRegister wd, GpuRegister rs, int offset);
+ void StW(VectorRegister wd, GpuRegister rs, int offset);
+ void StD(VectorRegister wd, GpuRegister rs, int offset);
+
// Higher level composite instructions.
int InstrCountForLoadReplicatedConst32(int64_t);
void LoadConst32(GpuRegister rd, int32_t value);
@@ -1380,6 +1476,17 @@
void EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd, int funct);
void EmitFI(int opcode, int fmt, FpuRegister rt, uint16_t imm);
void EmitBcondc(BranchCondition cond, GpuRegister rs, GpuRegister rt, uint32_t imm16_21);
+ void EmitMsa3R(int operation,
+ int df,
+ VectorRegister wt,
+ VectorRegister ws,
+ VectorRegister wd,
+ int minor_opcode);
+ void EmitMsaBIT(int operation, int df_m, VectorRegister ws, VectorRegister wd, int minor_opcode);
+ void EmitMsaELM(int operation, int df_n, VectorRegister ws, VectorRegister wd, int minor_opcode);
+ void EmitMsaMI10(int s10, GpuRegister rs, VectorRegister wd, int minor_opcode, int df);
+ void EmitMsa2R(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode);
+ void EmitMsa2RF(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode);
void Buncond(Mips64Label* label);
void Bcond(Mips64Label* label,
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index 879807a..b437bf0 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -37,12 +37,14 @@
class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler,
mips64::GpuRegister,
mips64::FpuRegister,
- uint32_t> {
+ uint32_t,
+ mips64::VectorRegister> {
public:
typedef AssemblerTest<mips64::Mips64Assembler,
mips64::GpuRegister,
mips64::FpuRegister,
- uint32_t> Base;
+ uint32_t,
+ mips64::VectorRegister> Base;
protected:
// Get the typically used name for this architecture, e.g., aarch64, x86-64, ...
@@ -60,7 +62,7 @@
// (and MIPS32R6) with the GNU assembler don't have correct final offsets in PC-relative
// branches in the .text section and so they require a relocation pass (there's a relocation
// section, .rela.text, that has the needed info to fix up the branches).
- return " -march=mips64r6 -Wa,--no-warn -Wl,-Ttext=0 -Wl,-e0 -nostdlib";
+ return " -march=mips64r6 -mmsa -Wa,--no-warn -Wl,-Ttext=0 -Wl,-e0 -nostdlib";
}
void Pad(std::vector<uint8_t>& data) OVERRIDE {
@@ -176,6 +178,39 @@
fp_registers_.push_back(new mips64::FpuRegister(mips64::F29));
fp_registers_.push_back(new mips64::FpuRegister(mips64::F30));
fp_registers_.push_back(new mips64::FpuRegister(mips64::F31));
+
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W0));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W1));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W2));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W3));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W4));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W5));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W6));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W7));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W8));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W9));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W10));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W11));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W12));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W13));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W14));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W15));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W16));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W17));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W18));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W19));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W20));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W21));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W22));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W23));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W24));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W25));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W26));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W27));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W28));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W29));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W30));
+ vec_registers_.push_back(new mips64::VectorRegister(mips64::W31));
}
}
@@ -183,6 +218,7 @@
AssemblerTest::TearDown();
STLDeleteElements(®isters_);
STLDeleteElements(&fp_registers_);
+ STLDeleteElements(&vec_registers_);
}
std::vector<mips64::GpuRegister*> GetRegisters() OVERRIDE {
@@ -193,6 +229,10 @@
return fp_registers_;
}
+ std::vector<mips64::VectorRegister*> GetVectorRegisters() OVERRIDE {
+ return vec_registers_;
+ }
+
uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
return imm_value;
}
@@ -272,6 +312,7 @@
std::map<mips64::GpuRegister, std::string, MIPS64CpuRegisterCompare> secondary_register_names_;
std::vector<mips64::FpuRegister*> fp_registers_;
+ std::vector<mips64::VectorRegister*> vec_registers_;
};
@@ -2450,6 +2491,370 @@
EXPECT_EQ(tester.GetPathsCovered(), art::mips64::kLoadConst64PathAllPaths);
}
+// MSA instructions.
+
+TEST_F(AssemblerMIPS64Test, AndV) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::AndV, "and.v ${reg1}, ${reg2}, ${reg3}"), "and.v");
+}
+
+TEST_F(AssemblerMIPS64Test, OrV) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::OrV, "or.v ${reg1}, ${reg2}, ${reg3}"), "or.v");
+}
+
+TEST_F(AssemblerMIPS64Test, NorV) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::NorV, "nor.v ${reg1}, ${reg2}, ${reg3}"), "nor.v");
+}
+
+TEST_F(AssemblerMIPS64Test, XorV) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::XorV, "xor.v ${reg1}, ${reg2}, ${reg3}"), "xor.v");
+}
+
+TEST_F(AssemblerMIPS64Test, AddvB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvB, "addv.b ${reg1}, ${reg2}, ${reg3}"),
+ "addv.b");
+}
+
+TEST_F(AssemblerMIPS64Test, AddvH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvH, "addv.h ${reg1}, ${reg2}, ${reg3}"),
+ "addv.h");
+}
+
+TEST_F(AssemblerMIPS64Test, AddvW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvW, "addv.w ${reg1}, ${reg2}, ${reg3}"),
+ "addv.w");
+}
+
+TEST_F(AssemblerMIPS64Test, AddvD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::AddvD, "addv.d ${reg1}, ${reg2}, ${reg3}"),
+ "addv.d");
+}
+
+TEST_F(AssemblerMIPS64Test, SubvB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvB, "subv.b ${reg1}, ${reg2}, ${reg3}"),
+ "subv.b");
+}
+
+TEST_F(AssemblerMIPS64Test, SubvH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvH, "subv.h ${reg1}, ${reg2}, ${reg3}"),
+ "subv.h");
+}
+
+TEST_F(AssemblerMIPS64Test, SubvW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvW, "subv.w ${reg1}, ${reg2}, ${reg3}"),
+ "subv.w");
+}
+
+TEST_F(AssemblerMIPS64Test, SubvD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SubvD, "subv.d ${reg1}, ${reg2}, ${reg3}"),
+ "subv.d");
+}
+
+TEST_F(AssemblerMIPS64Test, MulvB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvB, "mulv.b ${reg1}, ${reg2}, ${reg3}"),
+ "mulv.b");
+}
+
+TEST_F(AssemblerMIPS64Test, MulvH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvH, "mulv.h ${reg1}, ${reg2}, ${reg3}"),
+ "mulv.h");
+}
+
+TEST_F(AssemblerMIPS64Test, MulvW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvW, "mulv.w ${reg1}, ${reg2}, ${reg3}"),
+ "mulv.w");
+}
+
+TEST_F(AssemblerMIPS64Test, MulvD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::MulvD, "mulv.d ${reg1}, ${reg2}, ${reg3}"),
+ "mulv.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_sB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sB, "div_s.b ${reg1}, ${reg2}, ${reg3}"),
+ "div_s.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_sH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sH, "div_s.h ${reg1}, ${reg2}, ${reg3}"),
+ "div_s.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_sW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sW, "div_s.w ${reg1}, ${reg2}, ${reg3}"),
+ "div_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_sD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_sD, "div_s.d ${reg1}, ${reg2}, ${reg3}"),
+ "div_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_uB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uB, "div_u.b ${reg1}, ${reg2}, ${reg3}"),
+ "div_u.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_uH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uH, "div_u.h ${reg1}, ${reg2}, ${reg3}"),
+ "div_u.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_uW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uW, "div_u.w ${reg1}, ${reg2}, ${reg3}"),
+ "div_u.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Div_uD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Div_uD, "div_u.d ${reg1}, ${reg2}, ${reg3}"),
+ "div_u.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_sB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sB, "mod_s.b ${reg1}, ${reg2}, ${reg3}"),
+ "mod_s.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_sH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sH, "mod_s.h ${reg1}, ${reg2}, ${reg3}"),
+ "mod_s.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_sW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sW, "mod_s.w ${reg1}, ${reg2}, ${reg3}"),
+ "mod_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_sD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_sD, "mod_s.d ${reg1}, ${reg2}, ${reg3}"),
+ "mod_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_uB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uB, "mod_u.b ${reg1}, ${reg2}, ${reg3}"),
+ "mod_u.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_uH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uH, "mod_u.h ${reg1}, ${reg2}, ${reg3}"),
+ "mod_u.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_uW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uW, "mod_u.w ${reg1}, ${reg2}, ${reg3}"),
+ "mod_u.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Mod_uD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Mod_uD, "mod_u.d ${reg1}, ${reg2}, ${reg3}"),
+ "mod_u.d");
+}
+
+TEST_F(AssemblerMIPS64Test, FaddW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FaddW, "fadd.w ${reg1}, ${reg2}, ${reg3}"),
+ "fadd.w");
+}
+
+TEST_F(AssemblerMIPS64Test, FaddD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FaddD, "fadd.d ${reg1}, ${reg2}, ${reg3}"),
+ "fadd.d");
+}
+
+TEST_F(AssemblerMIPS64Test, FsubW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FsubW, "fsub.w ${reg1}, ${reg2}, ${reg3}"),
+ "fsub.w");
+}
+
+TEST_F(AssemblerMIPS64Test, FsubD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FsubD, "fsub.d ${reg1}, ${reg2}, ${reg3}"),
+ "fsub.d");
+}
+
+TEST_F(AssemblerMIPS64Test, FmulW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmulW, "fmul.w ${reg1}, ${reg2}, ${reg3}"),
+ "fmul.w");
+}
+
+TEST_F(AssemblerMIPS64Test, FmulD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmulD, "fmul.d ${reg1}, ${reg2}, ${reg3}"),
+ "fmul.d");
+}
+
+TEST_F(AssemblerMIPS64Test, FdivW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FdivW, "fdiv.w ${reg1}, ${reg2}, ${reg3}"),
+ "fdiv.w");
+}
+
+TEST_F(AssemblerMIPS64Test, FdivD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FdivD, "fdiv.d ${reg1}, ${reg2}, ${reg3}"),
+ "fdiv.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Ffint_sW) {
+ DriverStr(RepeatVV(&mips64::Mips64Assembler::Ffint_sW, "ffint_s.w ${reg1}, ${reg2}"),
+ "ffint_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Ffint_sD) {
+ DriverStr(RepeatVV(&mips64::Mips64Assembler::Ffint_sD, "ffint_s.d ${reg1}, ${reg2}"),
+ "ffint_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Ftint_sW) {
+ DriverStr(RepeatVV(&mips64::Mips64Assembler::Ftint_sW, "ftint_s.w ${reg1}, ${reg2}"),
+ "ftint_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Ftint_sD) {
+ DriverStr(RepeatVV(&mips64::Mips64Assembler::Ftint_sD, "ftint_s.d ${reg1}, ${reg2}"),
+ "ftint_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, SllB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllB, "sll.b ${reg1}, ${reg2}, ${reg3}"), "sll.b");
+}
+
+TEST_F(AssemblerMIPS64Test, SllH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllH, "sll.h ${reg1}, ${reg2}, ${reg3}"), "sll.h");
+}
+
+TEST_F(AssemblerMIPS64Test, SllW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllW, "sll.w ${reg1}, ${reg2}, ${reg3}"), "sll.w");
+}
+
+TEST_F(AssemblerMIPS64Test, SllD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SllD, "sll.d ${reg1}, ${reg2}, ${reg3}"), "sll.d");
+}
+
+TEST_F(AssemblerMIPS64Test, SraB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraB, "sra.b ${reg1}, ${reg2}, ${reg3}"), "sra.b");
+}
+
+TEST_F(AssemblerMIPS64Test, SraH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraH, "sra.h ${reg1}, ${reg2}, ${reg3}"), "sra.h");
+}
+
+TEST_F(AssemblerMIPS64Test, SraW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraW, "sra.w ${reg1}, ${reg2}, ${reg3}"), "sra.w");
+}
+
+TEST_F(AssemblerMIPS64Test, SraD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SraD, "sra.d ${reg1}, ${reg2}, ${reg3}"), "sra.d");
+}
+
+TEST_F(AssemblerMIPS64Test, SrlB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlB, "srl.b ${reg1}, ${reg2}, ${reg3}"), "srl.b");
+}
+
+TEST_F(AssemblerMIPS64Test, SrlH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlH, "srl.h ${reg1}, ${reg2}, ${reg3}"), "srl.h");
+}
+
+TEST_F(AssemblerMIPS64Test, SrlW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlW, "srl.w ${reg1}, ${reg2}, ${reg3}"), "srl.w");
+}
+
+TEST_F(AssemblerMIPS64Test, SrlD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::SrlD, "srl.d ${reg1}, ${reg2}, ${reg3}"), "srl.d");
+}
+
+TEST_F(AssemblerMIPS64Test, SlliB) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliB, 3, "slli.b ${reg1}, ${reg2}, {imm}"),
+ "slli.b");
+}
+
+TEST_F(AssemblerMIPS64Test, SlliH) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliH, 4, "slli.h ${reg1}, ${reg2}, {imm}"),
+ "slli.h");
+}
+
+TEST_F(AssemblerMIPS64Test, SlliW) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliW, 5, "slli.w ${reg1}, ${reg2}, {imm}"),
+ "slli.w");
+}
+
+TEST_F(AssemblerMIPS64Test, SlliD) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SlliD, 6, "slli.d ${reg1}, ${reg2}, {imm}"),
+ "slli.d");
+}
+
+TEST_F(AssemblerMIPS64Test, MoveV) {
+ DriverStr(RepeatVV(&mips64::Mips64Assembler::MoveV, "move.v ${reg1}, ${reg2}"), "move.v");
+}
+
+TEST_F(AssemblerMIPS64Test, SplatiB) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiB, 4, "splati.b ${reg1}, ${reg2}[{imm}]"),
+ "splati.b");
+}
+
+TEST_F(AssemblerMIPS64Test, SplatiH) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiH, 3, "splati.h ${reg1}, ${reg2}[{imm}]"),
+ "splati.h");
+}
+
+TEST_F(AssemblerMIPS64Test, SplatiW) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiW, 2, "splati.w ${reg1}, ${reg2}[{imm}]"),
+ "splati.w");
+}
+
+TEST_F(AssemblerMIPS64Test, SplatiD) {
+ DriverStr(RepeatVVIb(&mips64::Mips64Assembler::SplatiD, 1, "splati.d ${reg1}, ${reg2}[{imm}]"),
+ "splati.d");
+}
+
+TEST_F(AssemblerMIPS64Test, FillB) {
+ DriverStr(RepeatVR(&mips64::Mips64Assembler::FillB, "fill.b ${reg1}, ${reg2}"), "fill.b");
+}
+
+TEST_F(AssemblerMIPS64Test, FillH) {
+ DriverStr(RepeatVR(&mips64::Mips64Assembler::FillH, "fill.h ${reg1}, ${reg2}"), "fill.h");
+}
+
+TEST_F(AssemblerMIPS64Test, FillW) {
+ DriverStr(RepeatVR(&mips64::Mips64Assembler::FillW, "fill.w ${reg1}, ${reg2}"), "fill.w");
+}
+
+TEST_F(AssemblerMIPS64Test, FillD) {
+ DriverStr(RepeatVR(&mips64::Mips64Assembler::FillD, "fill.d ${reg1}, ${reg2}"), "fill.d");
+}
+
+TEST_F(AssemblerMIPS64Test, LdB) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdB, -10, "ld.b ${reg1}, {imm}(${reg2})"), "ld.b");
+}
+
+TEST_F(AssemblerMIPS64Test, LdH) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdH, -10, "ld.h ${reg1}, {imm}(${reg2})", 0, 2),
+ "ld.h");
+}
+
+TEST_F(AssemblerMIPS64Test, LdW) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdW, -10, "ld.w ${reg1}, {imm}(${reg2})", 0, 4),
+ "ld.w");
+}
+
+TEST_F(AssemblerMIPS64Test, LdD) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdD, -10, "ld.d ${reg1}, {imm}(${reg2})", 0, 8),
+ "ld.d");
+}
+
+TEST_F(AssemblerMIPS64Test, StB) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StB, -10, "st.b ${reg1}, {imm}(${reg2})"), "st.b");
+}
+
+TEST_F(AssemblerMIPS64Test, StH) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StH, -10, "st.h ${reg1}, {imm}(${reg2})", 0, 2),
+ "st.h");
+}
+
+TEST_F(AssemblerMIPS64Test, StW) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StW, -10, "st.w ${reg1}, {imm}(${reg2})", 0, 4),
+ "st.w");
+}
+
+TEST_F(AssemblerMIPS64Test, StD) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::StD, -10, "st.d ${reg1}, {imm}(${reg2})", 0, 8),
+ "st.d");
+}
+
#undef __
} // namespace art
diff --git a/compiler/utils/mips64/constants_mips64.h b/compiler/utils/mips64/constants_mips64.h
index f57498d..5ae9c73 100644
--- a/compiler/utils/mips64/constants_mips64.h
+++ b/compiler/utils/mips64/constants_mips64.h
@@ -51,8 +51,35 @@
kFdShift = 6,
kFdBits = 5,
+ kMsaOperationShift = 23,
+ kMsaELMOperationShift = 22,
+ kMsa2ROperationShift = 18,
+ kMsa2RFOperationShift = 17,
+ kDfShift = 21,
+ kDfMShift = 16,
+ kDf2RShift = 16,
+ kDfNShift = 16,
+ kWtShift = 16,
+ kWtBits = 5,
+ kWsShift = 11,
+ kWsBits = 5,
+ kWdShift = 6,
+ kWdBits = 5,
+ kS10Shift = 16,
+ kS10MinorShift = 2,
+
kBranchOffsetMask = 0x0000ffff,
kJumpOffsetMask = 0x03ffffff,
+ kMsaMajorOpcode = 0x1e,
+ kMsaDfMByteMask = 0x70,
+ kMsaDfMHalfwordMask = 0x60,
+ kMsaDfMWordMask = 0x40,
+ kMsaDfMDoublewordMask = 0x00,
+ kMsaDfNByteMask = 0x00,
+ kMsaDfNHalfwordMask = 0x20,
+ kMsaDfNWordMask = 0x30,
+ kMsaDfNDoublewordMask = 0x38,
+ kMsaS10Mask = 0x3ff,
};
enum ScaleFactor {
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 1f6b874..fc6c18b 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -43,6 +43,7 @@
static const uint32_t kOpcodeShift = 26;
static const uint32_t kCop1 = (17 << kOpcodeShift);
+static const uint32_t kMsa = (30 << kOpcodeShift); // MSA major opcode.
static const uint32_t kITypeMask = (0x3f << kOpcodeShift);
static const uint32_t kJTypeMask = (0x3f << kOpcodeShift);
@@ -51,6 +52,8 @@
static const uint32_t kSpecial2Mask = (0x3f << kOpcodeShift);
static const uint32_t kSpecial3Mask = (0x3f << kOpcodeShift);
static const uint32_t kFpMask = kRTypeMask;
+static const uint32_t kMsaMask = kRTypeMask;
+static const uint32_t kMsaSpecialMask = (0x3f << kOpcodeShift);
static const MipsInstruction gMipsInstructions[] = {
// "sll r0, r0, 0" is the canonical "nop", used in delay slots.
@@ -417,6 +420,36 @@
{ kFpMask, kCop1 | 0x10, "sel", "fadt" },
{ kFpMask, kCop1 | 0x1e, "max", "fadt" },
{ kFpMask, kCop1 | 0x1c, "min", "fadt" },
+
+ // MSA instructions.
+ { kMsaMask | (0x1f << 21), kMsa | (0x0 << 21) | 0x1e, "and.v", "kmn" },
+ { kMsaMask | (0x1f << 21), kMsa | (0x1 << 21) | 0x1e, "or.v", "kmn" },
+ { kMsaMask | (0x1f << 21), kMsa | (0x2 << 21) | 0x1e, "nor.v", "kmn" },
+ { kMsaMask | (0x1f << 21), kMsa | (0x3 << 21) | 0x1e, "xor.v", "kmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0xe, "addv", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x1 << 23) | 0xe, "subv", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0x12, "mulv", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0x12, "div_s", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0x12, "div_u", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x12, "mod_s", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x7 << 23) | 0x12, "mod_u", "Vkmn" },
+ { kMsaMask | (0xf << 22), kMsa | (0x0 << 22) | 0x1b, "fadd", "Ukmn" },
+ { kMsaMask | (0xf << 22), kMsa | (0x1 << 22) | 0x1b, "fsub", "Ukmn" },
+ { kMsaMask | (0xf << 22), kMsa | (0x2 << 22) | 0x1b, "fmul", "Ukmn" },
+ { kMsaMask | (0xf << 22), kMsa | (0x3 << 22) | 0x1b, "fdiv", "Ukmn" },
+ { kMsaMask | (0x1ff << 17), kMsa | (0x19e << 17) | 0x1e, "ffint_s", "ukm" },
+ { kMsaMask | (0x1ff << 17), kMsa | (0x19c << 17) | 0x1e, "ftint_s", "ukm" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0xd, "sll", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x1 << 23) | 0xd, "sra", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x2 << 23) | 0xd, "srl", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0x9, "slli", "kmW" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x1 << 23) | 0x9, "srai", "kmW" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x2 << 23) | 0x9, "srli", "kmW" },
+ { kMsaMask | (0x3ff << 16), kMsa | (0xbe << 16) | 0x19, "move.v", "km" },
+ { kMsaMask | (0xf << 22), kMsa | (0x1 << 22) | 0x19, "splati", "kX" },
+ { kMsaMask | (0xff << 18), kMsa | (0xc0 << 18) | 0x1e, "fill", "vkD" },
+ { kMsaSpecialMask | (0xf << 2), kMsa | (0x8 << 2), "ld", "kw" },
+ { kMsaSpecialMask | (0xf << 2), kMsa | (0x9 << 2), "st", "kw" },
};
static uint32_t ReadU32(const uint8_t* ptr) {
@@ -559,6 +592,111 @@
case 't': args << 'f' << rt; break;
case 'Z': args << (rd + 1); break; // sz ([d]ext size).
case 'z': args << (rd - sa + 1); break; // sz ([d]ins, dinsu size).
+ case 'k': args << 'w' << sa; break;
+ case 'm': args << 'w' << rd; break;
+ case 'n': args << 'w' << rt; break;
+ case 'U': // MSA 1-bit df (word/doubleword), position 21.
+ {
+ int32_t df = (instruction >> 21) & 0x1;
+ switch (df) {
+ case 0: opcode += ".w"; break;
+ case 1: opcode += ".d"; break;
+ }
+ continue; // No ", ".
+ }
+ case 'u': // MSA 1-bit df (word/doubleword), position 16.
+ {
+ int32_t df = (instruction >> 16) & 0x1;
+ switch (df) {
+ case 0: opcode += ".w"; break;
+ case 1: opcode += ".d"; break;
+ }
+ continue; // No ", ".
+ }
+ case 'V': // MSA 2-bit df, position 21.
+ {
+ int32_t df = (instruction >> 21) & 0x3;
+ switch (df) {
+ case 0: opcode += ".b"; break;
+ case 1: opcode += ".h"; break;
+ case 2: opcode += ".w"; break;
+ case 3: opcode += ".d"; break;
+ }
+ continue; // No ", ".
+ }
+ case 'v': // MSA 2-bit df, position 16.
+ {
+ int32_t df = (instruction >> 16) & 0x3;
+ switch (df) {
+ case 0: opcode += ".b"; break;
+ case 1: opcode += ".h"; break;
+ case 2: opcode += ".w"; break;
+ case 3: opcode += ".d"; break;
+ }
+ continue; // No ", ".
+ }
+ case 'W': // MSA df/m.
+ {
+ int32_t df_m = (instruction >> 16) & 0x7f;
+ if ((df_m & (0x1 << 6)) == 0) {
+ opcode += ".d";
+ args << (df_m & 0x3f);
+ break;
+ }
+ if ((df_m & (0x1 << 5)) == 0) {
+ opcode += ".w";
+ args << (df_m & 0x1f);
+ break;
+ }
+ if ((df_m & (0x1 << 4)) == 0) {
+ opcode += ".h";
+ args << (df_m & 0xf);
+ break;
+ }
+ if ((df_m & (0x1 << 3)) == 0) {
+ opcode += ".b";
+ args << (df_m & 0x7);
+ }
+ break;
+ }
+ case 'w': // MSA +x(rs).
+ {
+ int32_t df = instruction & 0x3;
+ int32_t s10 = (instruction >> 16) & 0x3ff;
+ s10 -= (s10 & 0x200) << 1; // Sign-extend s10.
+ switch (df) {
+ case 0: opcode += ".b"; break;
+ case 1: opcode += ".h"; break;
+ case 2: opcode += ".w"; break;
+ case 3: opcode += ".d"; break;
+ }
+ args << StringPrintf("%+d(r%d)", s10 << df, rd);
+ break;
+ }
+ case 'X': // MSA df/n - ws[x].
+ {
+ int32_t df_n = (instruction >> 16) & 0x3f;
+ if ((df_n & (0x3 << 4)) == 0) {
+ opcode += ".b";
+ args << 'w' << rd << '[' << (df_n & 0xf) << ']';
+ break;
+ }
+ if ((df_n & (0x3 << 3)) == 0) {
+ opcode += ".h";
+ args << 'w' << rd << '[' << (df_n & 0x7) << ']';
+ break;
+ }
+ if ((df_n & (0x3 << 2)) == 0) {
+ opcode += ".w";
+ args << 'w' << rd << '[' << (df_n & 0x3) << ']';
+ break;
+ }
+ if ((df_n & (0x3 << 1)) == 0) {
+ opcode += ".d";
+ args << 'w' << rd << '[' << (df_n & 0x1) << ']';
+ }
+ break;
+ }
}
if (*(args_fmt + 1)) {
args << ", ";
diff --git a/runtime/arch/mips64/registers_mips64.cc b/runtime/arch/mips64/registers_mips64.cc
index 4959208..1ee2cdd 100644
--- a/runtime/arch/mips64/registers_mips64.cc
+++ b/runtime/arch/mips64/registers_mips64.cc
@@ -46,5 +46,14 @@
return os;
}
+std::ostream& operator<<(std::ostream& os, const VectorRegister& rhs) {
+ if (rhs >= W0 && rhs < kNumberOfVectorRegisters) {
+ os << "w" << static_cast<int>(rhs);
+ } else {
+ os << "VectorRegister[" << static_cast<int>(rhs) << "]";
+ }
+ return os;
+}
+
} // namespace mips64
} // namespace art
diff --git a/runtime/arch/mips64/registers_mips64.h b/runtime/arch/mips64/registers_mips64.h
index 81fae72..30de2cc 100644
--- a/runtime/arch/mips64/registers_mips64.h
+++ b/runtime/arch/mips64/registers_mips64.h
@@ -107,6 +107,45 @@
};
std::ostream& operator<<(std::ostream& os, const FpuRegister& rhs);
+// Values for vector registers.
+enum VectorRegister {
+ W0 = 0,
+ W1 = 1,
+ W2 = 2,
+ W3 = 3,
+ W4 = 4,
+ W5 = 5,
+ W6 = 6,
+ W7 = 7,
+ W8 = 8,
+ W9 = 9,
+ W10 = 10,
+ W11 = 11,
+ W12 = 12,
+ W13 = 13,
+ W14 = 14,
+ W15 = 15,
+ W16 = 16,
+ W17 = 17,
+ W18 = 18,
+ W19 = 19,
+ W20 = 20,
+ W21 = 21,
+ W22 = 22,
+ W23 = 23,
+ W24 = 24,
+ W25 = 25,
+ W26 = 26,
+ W27 = 27,
+ W28 = 28,
+ W29 = 29,
+ W30 = 30,
+ W31 = 31,
+ kNumberOfVectorRegisters = 32,
+ kNoVectorRegister = -1,
+};
+std::ostream& operator<<(std::ostream& os, const VectorRegister& rhs);
+
} // namespace mips64
} // namespace art