summaryrefslogtreecommitdiff
path: root/compiler/utils
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/utils')
-rw-r--r--compiler/utils/assembler_test.h18
-rw-r--r--compiler/utils/mips/assembler_mips.cc278
-rw-r--r--compiler/utils/mips/assembler_mips.h57
-rw-r--r--compiler/utils/mips/assembler_mips32r6_test.cc126
-rw-r--r--compiler/utils/mips/assembler_mips_test.cc80
-rw-r--r--compiler/utils/mips64/assembler_mips64.cc156
-rw-r--r--compiler/utils/mips64/assembler_mips64.h30
-rw-r--r--compiler/utils/mips64/assembler_mips64_test.cc145
8 files changed, 872 insertions, 18 deletions
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index ae7636b106..ad84412ef5 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -650,6 +650,24 @@ class AssemblerTest : public testing::Test {
}
template <typename ImmType>
+ std::string RepeatRVIb(void (Ass::*f)(Reg, VecReg, ImmType),
+ int imm_bits,
+ const std::string& fmt,
+ int bias = 0,
+ int multiplier = 1) {
+ return RepeatTemplatedRegistersImmBits<Reg, VecReg, ImmType>(
+ f,
+ imm_bits,
+ GetRegisters(),
+ GetVectorRegisters(),
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ &AssemblerTest::GetVecRegName,
+ fmt,
+ bias,
+ multiplier);
+ }
+
+ template <typename ImmType>
std::string RepeatVVIb(void (Ass::*f)(VecReg, VecReg, ImmType),
int imm_bits,
const std::string& fmt,
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index b83e3f5471..cbb2c0ea47 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -2800,6 +2800,74 @@ void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
static_cast<FRegister>(ws));
}
+void MipsAssembler::Copy_sB(Register rd, VectorRegister ws, int n4) {
+ CHECK(HasMsa());
+ CHECK(IsUint<4>(n4)) << n4;
+ DsFsmInstrRf(EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19),
+ rd,
+ static_cast<FRegister>(ws));
+}
+
+void MipsAssembler::Copy_sH(Register rd, VectorRegister ws, int n3) {
+ CHECK(HasMsa());
+ CHECK(IsUint<3>(n3)) << n3;
+ DsFsmInstrRf(EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19),
+ rd,
+ static_cast<FRegister>(ws));
+}
+
+void MipsAssembler::Copy_sW(Register rd, VectorRegister ws, int n2) {
+ CHECK(HasMsa());
+ CHECK(IsUint<2>(n2)) << n2;
+ DsFsmInstrRf(EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19),
+ rd,
+ static_cast<FRegister>(ws));
+}
+
+void MipsAssembler::Copy_uB(Register rd, VectorRegister ws, int n4) {
+ CHECK(HasMsa());
+ CHECK(IsUint<4>(n4)) << n4;
+ DsFsmInstrRf(EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19),
+ rd,
+ static_cast<FRegister>(ws));
+}
+
+void MipsAssembler::Copy_uH(Register rd, VectorRegister ws, int n3) {
+ CHECK(HasMsa());
+ CHECK(IsUint<3>(n3)) << n3;
+ DsFsmInstrRf(EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19),
+ rd,
+ static_cast<FRegister>(ws));
+}
+
+void MipsAssembler::InsertB(VectorRegister wd, Register rs, int n4) {
+ CHECK(HasMsa());
+ CHECK(IsUint<4>(n4)) << n4;
+ DsFsmInstrFffr(EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(wd),
+ rs);
+}
+
+void MipsAssembler::InsertH(VectorRegister wd, Register rs, int n3) {
+ CHECK(HasMsa());
+ CHECK(IsUint<3>(n3)) << n3;
+ DsFsmInstrFffr(
+ EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(wd),
+ rs);
+}
+
+void MipsAssembler::InsertW(VectorRegister wd, Register rs, int n2) {
+ CHECK(HasMsa());
+ CHECK(IsUint<2>(n2)) << n2;
+ DsFsmInstrFffr(EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(wd),
+ rs);
+}
+
void MipsAssembler::FillB(VectorRegister wd, Register rs) {
CHECK(HasMsa());
DsFsmInstrFr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e),
@@ -2921,6 +2989,38 @@ void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) {
rs);
}
+void MipsAssembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14),
@@ -2953,6 +3053,70 @@ void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister w
static_cast<FRegister>(wt));
}
+void MipsAssembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
void MipsAssembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12),
@@ -3049,6 +3213,54 @@ void MipsAssembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister
static_cast<FRegister>(wt));
}
+void MipsAssembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
+void MipsAssembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15),
+ static_cast<FRegister>(wd),
+ static_cast<FRegister>(ws),
+ static_cast<FRegister>(wt));
+}
+
void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst,
FRegister src,
bool is_double) {
@@ -3353,8 +3565,6 @@ MipsAssembler::Branch::Branch(bool is_r6,
CHECK_NE(dest_reg, ZERO);
if (is_r6) {
CHECK_EQ(base_reg, ZERO);
- } else {
- CHECK_NE(base_reg, ZERO);
}
InitializeType(label_or_literal_type, is_r6);
}
@@ -3646,15 +3856,29 @@ uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch
case Branch::kFarLabel:
case Branch::kLiteral:
case Branch::kFarLiteral:
- return GetLabelLocation(&pc_rel_base_label_);
+ if (branch->GetRightRegister() != ZERO) {
+ return GetLabelLocation(&pc_rel_base_label_);
+ }
+ // For those label/literal loads which come with their own NAL instruction
+ // and don't depend on `pc_rel_base_label_` we can simply use the location
+ // of the "branch" (the NAL precedes the "branch" immediately). The location
+ // is close enough for the user of the returned location, PromoteIfNeeded(),
+ // to not miss needed promotion to a far load.
+ // (GetOffsetSizeNeeded() provides a little leeway by means of kMaxBranchSize,
+ // which is larger than all composite branches and label/literal loads: it's
+ // OK to promote a bit earlier than strictly necessary, it makes things
+ // simpler.)
+ FALLTHROUGH_INTENDED;
default:
return branch->GetLocation();
}
}
uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) {
- // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
- // `this->GetLocation()` for everything else.
+ // `location` comes from GetBranchLocationOrPcRelBase() and is either the location
+ // of the PC-relative branch or (for some R2 label and literal loads) the location
+ // of `pc_rel_base_label_`. The PC-relative offset of the branch/load is relative
+ // to this location.
// If the branch is still unresolved or already long, nothing to do.
if (IsLong() || !IsResolved()) {
return 0;
@@ -3695,7 +3919,15 @@ uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Bra
case Branch::kFarLabel:
case Branch::kLiteral:
case Branch::kFarLiteral:
- return GetLabelLocation(&pc_rel_base_label_);
+ if (branch->GetRightRegister() == ZERO) {
+ // These loads don't use `pc_rel_base_label_` and instead rely on their own
+ // NAL instruction (it immediately precedes the "branch"). Therefore the
+ // effective PC-relative base register is RA and it corresponds to the 2nd
+ // instruction after the NAL.
+ return branch->GetLocation() + sizeof(uint32_t);
+ } else {
+ return GetLabelLocation(&pc_rel_base_label_);
+ }
default:
return branch->GetOffsetLocation() +
Branch::branch_info_[branch->GetType()].pc_org * sizeof(uint32_t);
@@ -3703,9 +3935,10 @@ uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Bra
}
uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const {
- // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
- // `this->GetOffsetLocation() + branch_info_[this->GetType()].pc_org * sizeof(uint32_t)`
- // for everything else.
+ // `location` comes from GetBranchOrPcRelBaseForEncoding() and is either a location
+ // within/near the PC-relative branch or (for some R2 label and literal loads) the
+ // location of `pc_rel_base_label_`. The PC-relative offset of the branch/load is
+ // relative to this location.
CHECK(IsResolved());
uint32_t ofs_mask = 0xFFFFFFFF >> (32 - GetOffsetSize());
// Calculate the byte distance between instructions and also account for
@@ -4001,6 +4234,12 @@ void MipsAssembler::Call(MipsLabel* label, bool is_r6, bool is_bare) {
void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) {
// Label address loads are treated as pseudo branches since they require very similar handling.
DCHECK(!label->IsBound());
+ // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we
+ // may generate an individual NAL instruction to simulate PC-relative addressing on R2
+ // by specifying `base_reg` of `ZERO`. Check for it.
+ if (base_reg == ZERO && !IsR6()) {
+ Nal();
+ }
branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel);
FinalizeLabeledBranch(label);
}
@@ -4016,6 +4255,12 @@ void MipsAssembler::LoadLiteral(Register dest_reg, Register base_reg, Literal* l
DCHECK_EQ(literal->GetSize(), 4u);
MipsLabel* label = literal->GetLabel();
DCHECK(!label->IsBound());
+ // If `pc_rel_base_label_` isn't bound or none of registers contains its address, we
+ // may generate an individual NAL instruction to simulate PC-relative addressing on R2
+ // by specifying `base_reg` of `ZERO`. Check for it.
+ if (base_reg == ZERO && !IsR6()) {
+ Nal();
+ }
branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral);
FinalizeLabeledBranch(label);
}
@@ -4203,6 +4448,13 @@ static inline bool IsAbsorbableInstruction(uint32_t instruction) {
}
}
+static inline Register GetR2PcRelBaseRegister(Register reg) {
+ // LoadLabelAddress() and LoadLiteral() generate individual NAL
+ // instructions on R2 when the specified base register is ZERO
+ // and so the effective PC-relative base register is RA, not ZERO.
+ return (reg == ZERO) ? RA : reg;
+}
+
// Note: make sure branch_info_[] and EmitBranch() are kept synchronized.
void MipsAssembler::EmitBranch(uint32_t branch_id) {
CHECK_EQ(overwriting_, true);
@@ -4293,13 +4545,13 @@ void MipsAssembler::EmitBranch(uint32_t branch_id) {
case Branch::kLabel:
DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
- Addiu(lhs, rhs, offset);
+ Addiu(lhs, GetR2PcRelBaseRegister(rhs), offset);
break;
// R2 near literal.
case Branch::kLiteral:
DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
- Lw(lhs, rhs, offset);
+ Lw(lhs, GetR2PcRelBaseRegister(rhs), offset);
break;
// R2 long branches.
@@ -4378,7 +4630,7 @@ void MipsAssembler::EmitBranch(uint32_t branch_id) {
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Lui(AT, High16Bits(offset));
Ori(AT, AT, Low16Bits(offset));
- Addu(lhs, AT, rhs);
+ Addu(lhs, AT, GetR2PcRelBaseRegister(rhs));
break;
// R2 far literal.
case Branch::kFarLiteral:
@@ -4386,7 +4638,7 @@ void MipsAssembler::EmitBranch(uint32_t branch_id) {
offset += (offset & 0x8000) << 1; // Account for sign extension in lw.
CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
Lui(AT, High16Bits(offset));
- Addu(AT, AT, rhs);
+ Addu(AT, AT, GetR2PcRelBaseRegister(rhs));
Lw(lhs, AT, Low16Bits(offset));
break;
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 57b3edd03a..c0ea29fbd7 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -601,6 +601,14 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
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 Copy_sB(Register rd, VectorRegister ws, int n4);
+ void Copy_sH(Register rd, VectorRegister ws, int n3);
+ void Copy_sW(Register rd, VectorRegister ws, int n2);
+ void Copy_uB(Register rd, VectorRegister ws, int n4);
+ void Copy_uH(Register rd, VectorRegister ws, int n3);
+ void InsertB(VectorRegister wd, Register rs, int n4);
+ void InsertH(VectorRegister wd, Register rs, int n3);
+ void InsertW(VectorRegister wd, Register rs, int n2);
void FillB(VectorRegister wd, Register rs);
void FillH(VectorRegister wd, Register rs);
void FillW(VectorRegister wd, Register rs);
@@ -618,10 +626,22 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
void StW(VectorRegister wd, Register rs, int offset);
void StD(VectorRegister wd, Register rs, int offset);
+ void IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
@@ -636,6 +656,13 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
void FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+
// Helper for replicating floating point value in all destination elements.
void ReplicateFPToVectorRegister(VectorRegister dst, FRegister src, bool is_double);
@@ -1061,16 +1088,36 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
}
- // Load label address using the base register (for R2 only) or using PC-relative loads
- // (for R6 only; base_reg must be ZERO). To be used with data labels in the literal /
- // jump table area only and not with regular code labels.
+ // Load label address using PC-relative addressing.
+ // To be used with data labels in the literal / jump table area only and not
+ // with regular code labels.
+ //
+ // For R6 base_reg must be ZERO.
+ //
+ // On R2 there are two possible uses w.r.t. base_reg:
+ //
+ // - base_reg = ZERO:
+ // The NAL instruction will be generated as part of the load and it will
+ // clobber the RA register.
+ //
+ // - base_reg != ZERO:
+ // The RA-clobbering NAL instruction won't be generated as part of the load.
+ // The label pc_rel_base_label_ must be bound (with BindPcRelBaseLabel())
+ // and base_reg must hold the address of the label. Example:
+ // __ Nal();
+ // __ Move(S3, RA);
+ // __ BindPcRelBaseLabel(); // S3 holds the address of pc_rel_base_label_.
+ // __ LoadLabelAddress(A0, S3, label1);
+ // __ LoadLabelAddress(A1, S3, label2);
+ // __ LoadLiteral(V0, S3, literal1);
+ // __ LoadLiteral(V1, S3, literal2);
void LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label);
// Create a new literal with the given data.
Literal* NewLiteral(size_t size, const uint8_t* data);
- // Load literal using the base register (for R2 only) or using PC-relative loads
- // (for R6 only; base_reg must be ZERO).
+ // Load literal using PC-relative addressing.
+ // See the above comments for LoadLabelAddress() on the value of base_reg.
void LoadLiteral(Register dest_reg, Register base_reg, Literal* literal);
// Create a jump table for the given labels that will be emitted when finalizing.
diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc
index b12b6b651c..c76a568ddd 100644
--- a/compiler/utils/mips/assembler_mips32r6_test.cc
+++ b/compiler/utils/mips/assembler_mips32r6_test.cc
@@ -2185,6 +2185,46 @@ TEST_F(AssemblerMIPS32r6Test, SplatiD) {
"splati.d");
}
+TEST_F(AssemblerMIPS32r6Test, Copy_sB) {
+ DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_sB, 4, "copy_s.b ${reg1}, ${reg2}[{imm}]"),
+ "copy_s.b");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Copy_sH) {
+ DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_sH, 3, "copy_s.h ${reg1}, ${reg2}[{imm}]"),
+ "copy_s.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Copy_sW) {
+ DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_sW, 2, "copy_s.w ${reg1}, ${reg2}[{imm}]"),
+ "copy_s.w");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Copy_uB) {
+ DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_uB, 4, "copy_u.b ${reg1}, ${reg2}[{imm}]"),
+ "copy_u.b");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Copy_uH) {
+ DriverStr(RepeatRVIb(&mips::MipsAssembler::Copy_uH, 3, "copy_u.h ${reg1}, ${reg2}[{imm}]"),
+ "copy_u.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, InsertB) {
+ DriverStr(RepeatVRIb(&mips::MipsAssembler::InsertB, 4, "insert.b ${reg1}[{imm}], ${reg2}"),
+ "insert.b");
+}
+
+TEST_F(AssemblerMIPS32r6Test, InsertH) {
+ DriverStr(RepeatVRIb(&mips::MipsAssembler::InsertH, 3, "insert.h ${reg1}[{imm}], ${reg2}"),
+ "insert.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, InsertW) {
+ DriverStr(RepeatVRIb(&mips::MipsAssembler::InsertW, 2, "insert.w ${reg1}[{imm}], ${reg2}"),
+ "insert.w");
+}
+
TEST_F(AssemblerMIPS32r6Test, FillB) {
DriverStr(RepeatVR(&mips::MipsAssembler::FillB, "fill.b ${reg1}, ${reg2}"), "fill.b");
}
@@ -2251,6 +2291,22 @@ TEST_F(AssemblerMIPS32r6Test, StD) {
"st.d");
}
+TEST_F(AssemblerMIPS32r6Test, IlvlB) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlB, "ilvl.b ${reg1}, ${reg2}, ${reg3}"), "ilvl.b");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvlH) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlH, "ilvl.h ${reg1}, ${reg2}, ${reg3}"), "ilvl.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvlW) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlW, "ilvl.w ${reg1}, ${reg2}, ${reg3}"), "ilvl.w");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvlD) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvlD, "ilvl.d ${reg1}, ${reg2}, ${reg3}"), "ilvl.d");
+}
+
TEST_F(AssemblerMIPS32r6Test, IlvrB) {
DriverStr(RepeatVVV(&mips::MipsAssembler::IlvrB, "ilvr.b ${reg1}, ${reg2}, ${reg3}"), "ilvr.b");
}
@@ -2267,6 +2323,46 @@ TEST_F(AssemblerMIPS32r6Test, IlvrD) {
DriverStr(RepeatVVV(&mips::MipsAssembler::IlvrD, "ilvr.d ${reg1}, ${reg2}, ${reg3}"), "ilvr.d");
}
+TEST_F(AssemblerMIPS32r6Test, IlvevB) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevB, "ilvev.b ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.b");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvevH) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevH, "ilvev.h ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvevW) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevW, "ilvev.w ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.w");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvevD) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvevD, "ilvev.d ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.d");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvodB) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodB, "ilvod.b ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.b");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvodH) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodH, "ilvod.h ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvodW) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodW, "ilvod.w ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.w");
+}
+
+TEST_F(AssemblerMIPS32r6Test, IlvodD) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::IlvodD, "ilvod.d ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.d");
+}
+
TEST_F(AssemblerMIPS32r6Test, MaddvB) {
DriverStr(RepeatVVV(&mips::MipsAssembler::MaddvB, "maddv.b ${reg1}, ${reg2}, ${reg3}"),
"maddv.b");
@@ -2287,6 +2383,36 @@ TEST_F(AssemblerMIPS32r6Test, MaddvD) {
"maddv.d");
}
+TEST_F(AssemblerMIPS32r6Test, Hadd_sH) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_sH, "hadd_s.h ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_s.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Hadd_sW) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_sW, "hadd_s.w ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_s.w");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Hadd_sD) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_sD, "hadd_s.d ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_s.d");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Hadd_uH) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_uH, "hadd_u.h ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_u.h");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Hadd_uW) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_uW, "hadd_u.w ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_u.w");
+}
+
+TEST_F(AssemblerMIPS32r6Test, Hadd_uD) {
+ DriverStr(RepeatVVV(&mips::MipsAssembler::Hadd_uD, "hadd_u.d ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_u.d");
+}
+
TEST_F(AssemblerMIPS32r6Test, MsubvB) {
DriverStr(RepeatVVV(&mips::MipsAssembler::MsubvB, "msubv.b ${reg1}, ${reg2}, ${reg3}"),
"msubv.b");
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index eed83a5528..9397be4c09 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -2913,6 +2913,46 @@ TEST_F(AssemblerMIPSTest, LoadNearestFarLabelAddress) {
DriverStr(expected, "LoadNearestFarLabelAddress");
}
+TEST_F(AssemblerMIPSTest, LoadFarthestNearLabelAddressUsingNal) {
+ mips::MipsLabel label;
+ __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
+ constexpr size_t kAddiuCount = 0x1FDE;
+ for (size_t i = 0; i != kAddiuCount; ++i) {
+ __ Addiu(mips::A0, mips::A1, 0);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ ".set noreorder\n"
+ "bltzal $zero, .+4\n"
+ "addiu $v0, $ra, %lo(2f - 1f)\n"
+ "1:\n" +
+ RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") +
+ "2:\n";
+ DriverStr(expected, "LoadFarthestNearLabelAddressUsingNal");
+}
+
+TEST_F(AssemblerMIPSTest, LoadNearestFarLabelAddressUsingNal) {
+ mips::MipsLabel label;
+ __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
+ constexpr size_t kAdduCount = 0x1FDF;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+ __ Bind(&label);
+
+ std::string expected =
+ ".set noreorder\n"
+ "bltzal $zero, .+4\n"
+ "lui $at, %hi(2f - 1f)\n"
+ "1:\n"
+ "ori $at, $at, %lo(2f - 1b)\n"
+ "addu $v0, $at, $ra\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n";
+ DriverStr(expected, "LoadNearestFarLabelAddressUsingNal");
+}
+
TEST_F(AssemblerMIPSTest, LoadFarthestNearLiteral) {
mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
__ BindPcRelBaseLabel();
@@ -2951,6 +2991,46 @@ TEST_F(AssemblerMIPSTest, LoadNearestFarLiteral) {
DriverStr(expected, "LoadNearestFarLiteral");
}
+TEST_F(AssemblerMIPSTest, LoadFarthestNearLiteralUsingNal) {
+ mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips::V0, mips::ZERO, literal);
+ constexpr size_t kAddiuCount = 0x1FDE;
+ for (size_t i = 0; i != kAddiuCount; ++i) {
+ __ Addiu(mips::A0, mips::A1, 0);
+ }
+
+ std::string expected =
+ ".set noreorder\n"
+ "bltzal $zero, .+4\n"
+ "lw $v0, %lo(2f - 1f)($ra)\n"
+ "1:\n" +
+ RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") +
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadFarthestNearLiteralUsingNal");
+}
+
+TEST_F(AssemblerMIPSTest, LoadNearestFarLiteralUsingNal) {
+ mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
+ __ LoadLiteral(mips::V0, mips::ZERO, literal);
+ constexpr size_t kAdduCount = 0x1FDF;
+ for (size_t i = 0; i != kAdduCount; ++i) {
+ __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+ }
+
+ std::string expected =
+ ".set noreorder\n"
+ "bltzal $zero, .+4\n"
+ "lui $at, %hi(2f - 1f)\n"
+ "1:\n"
+ "addu $at, $at, $ra\n"
+ "lw $v0, %lo(2f - 1b)($at)\n" +
+ RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadNearestFarLiteralUsingNal");
+}
+
#undef __
} // namespace art
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 606d4c39d0..d8a4531ac2 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -1874,6 +1874,72 @@ void Mips64Assembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19);
}
+void Mips64Assembler::Copy_sB(GpuRegister rd, VectorRegister ws, int n4) {
+ CHECK(HasMsa());
+ CHECK(IsUint<4>(n4)) << n4;
+ EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19);
+}
+
+void Mips64Assembler::Copy_sH(GpuRegister rd, VectorRegister ws, int n3) {
+ CHECK(HasMsa());
+ CHECK(IsUint<3>(n3)) << n3;
+ EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19);
+}
+
+void Mips64Assembler::Copy_sW(GpuRegister rd, VectorRegister ws, int n2) {
+ CHECK(HasMsa());
+ CHECK(IsUint<2>(n2)) << n2;
+ EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19);
+}
+
+void Mips64Assembler::Copy_sD(GpuRegister rd, VectorRegister ws, int n1) {
+ CHECK(HasMsa());
+ CHECK(IsUint<1>(n1)) << n1;
+ EmitMsaELM(0x2, n1 | kMsaDfNDoublewordMask, ws, static_cast<VectorRegister>(rd), 0x19);
+}
+
+void Mips64Assembler::Copy_uB(GpuRegister rd, VectorRegister ws, int n4) {
+ CHECK(HasMsa());
+ CHECK(IsUint<4>(n4)) << n4;
+ EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19);
+}
+
+void Mips64Assembler::Copy_uH(GpuRegister rd, VectorRegister ws, int n3) {
+ CHECK(HasMsa());
+ CHECK(IsUint<3>(n3)) << n3;
+ EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19);
+}
+
+void Mips64Assembler::Copy_uW(GpuRegister rd, VectorRegister ws, int n2) {
+ CHECK(HasMsa());
+ CHECK(IsUint<2>(n2)) << n2;
+ EmitMsaELM(0x3, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19);
+}
+
+void Mips64Assembler::InsertB(VectorRegister wd, GpuRegister rs, int n4) {
+ CHECK(HasMsa());
+ CHECK(IsUint<4>(n4)) << n4;
+ EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19);
+}
+
+void Mips64Assembler::InsertH(VectorRegister wd, GpuRegister rs, int n3) {
+ CHECK(HasMsa());
+ CHECK(IsUint<3>(n3)) << n3;
+ EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19);
+}
+
+void Mips64Assembler::InsertW(VectorRegister wd, GpuRegister rs, int n2) {
+ CHECK(HasMsa());
+ CHECK(IsUint<2>(n2)) << n2;
+ EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19);
+}
+
+void Mips64Assembler::InsertD(VectorRegister wd, GpuRegister rs, int n1) {
+ CHECK(HasMsa());
+ CHECK(IsUint<1>(n1)) << n1;
+ EmitMsaELM(0x4, n1 | kMsaDfNDoublewordMask, static_cast<VectorRegister>(rs), wd, 0x19);
+}
+
void Mips64Assembler::FillB(VectorRegister wd, GpuRegister rs) {
CHECK(HasMsa());
EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e);
@@ -1972,6 +2038,26 @@ void Mips64Assembler::StD(VectorRegister wd, GpuRegister rs, int offset) {
EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3);
}
+void Mips64Assembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14);
+}
+
void Mips64Assembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14);
@@ -1992,6 +2078,46 @@ void Mips64Assembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister
EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14);
}
+void Mips64Assembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14);
+}
+
+void Mips64Assembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14);
+}
+
void Mips64Assembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12);
@@ -2052,6 +2178,36 @@ void Mips64Assembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegiste
EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b);
}
+void Mips64Assembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15);
+}
+
+void Mips64Assembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15);
+}
+
+void Mips64Assembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15);
+}
+
+void Mips64Assembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15);
+}
+
+void Mips64Assembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15);
+}
+
+void Mips64Assembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15);
+}
+
void Mips64Assembler::ReplicateFPToVectorRegister(VectorRegister dst,
FpuRegister src,
bool is_double) {
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index a3787ac6ae..d67fb0054d 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -785,6 +785,17 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
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 Copy_sB(GpuRegister rd, VectorRegister ws, int n4);
+ void Copy_sH(GpuRegister rd, VectorRegister ws, int n3);
+ void Copy_sW(GpuRegister rd, VectorRegister ws, int n2);
+ void Copy_sD(GpuRegister rd, VectorRegister ws, int n1);
+ void Copy_uB(GpuRegister rd, VectorRegister ws, int n4);
+ void Copy_uH(GpuRegister rd, VectorRegister ws, int n3);
+ void Copy_uW(GpuRegister rd, VectorRegister ws, int n2);
+ void InsertB(VectorRegister wd, GpuRegister rs, int n4);
+ void InsertH(VectorRegister wd, GpuRegister rs, int n3);
+ void InsertW(VectorRegister wd, GpuRegister rs, int n2);
+ void InsertD(VectorRegister wd, GpuRegister rs, int n1);
void FillB(VectorRegister wd, GpuRegister rs);
void FillH(VectorRegister wd, GpuRegister rs);
void FillW(VectorRegister wd, GpuRegister rs);
@@ -803,10 +814,22 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void StW(VectorRegister wd, GpuRegister rs, int offset);
void StD(VectorRegister wd, GpuRegister rs, int offset);
+ void IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
@@ -821,6 +844,13 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+
// Helper for replicating floating point value in all destination elements.
void ReplicateFPToVectorRegister(VectorRegister dst, FpuRegister src, bool is_double);
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index bf0326de87..164af7891c 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -3399,6 +3399,61 @@ TEST_F(AssemblerMIPS64Test, SplatiD) {
"splati.d");
}
+TEST_F(AssemblerMIPS64Test, Copy_sB) {
+ DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sB, 4, "copy_s.b ${reg1}, ${reg2}[{imm}]"),
+ "copy_s.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Copy_sH) {
+ DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sH, 3, "copy_s.h ${reg1}, ${reg2}[{imm}]"),
+ "copy_s.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Copy_sW) {
+ DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sW, 2, "copy_s.w ${reg1}, ${reg2}[{imm}]"),
+ "copy_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Copy_sD) {
+ DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_sD, 1, "copy_s.d ${reg1}, ${reg2}[{imm}]"),
+ "copy_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Copy_uB) {
+ DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_uB, 4, "copy_u.b ${reg1}, ${reg2}[{imm}]"),
+ "copy_u.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Copy_uH) {
+ DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_uH, 3, "copy_u.h ${reg1}, ${reg2}[{imm}]"),
+ "copy_u.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Copy_uW) {
+ DriverStr(RepeatRVIb(&mips64::Mips64Assembler::Copy_uW, 2, "copy_u.w ${reg1}, ${reg2}[{imm}]"),
+ "copy_u.w");
+}
+
+TEST_F(AssemblerMIPS64Test, InsertB) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertB, 4, "insert.b ${reg1}[{imm}], ${reg2}"),
+ "insert.b");
+}
+
+TEST_F(AssemblerMIPS64Test, InsertH) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertH, 3, "insert.h ${reg1}[{imm}], ${reg2}"),
+ "insert.h");
+}
+
+TEST_F(AssemblerMIPS64Test, InsertW) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertW, 2, "insert.w ${reg1}[{imm}], ${reg2}"),
+ "insert.w");
+}
+
+TEST_F(AssemblerMIPS64Test, InsertD) {
+ DriverStr(RepeatVRIb(&mips64::Mips64Assembler::InsertD, 1, "insert.d ${reg1}[{imm}], ${reg2}"),
+ "insert.d");
+}
+
TEST_F(AssemblerMIPS64Test, FillB) {
DriverStr(RepeatVR(&mips64::Mips64Assembler::FillB, "fill.b ${reg1}, ${reg2}"), "fill.b");
}
@@ -3469,6 +3524,26 @@ TEST_F(AssemblerMIPS64Test, StD) {
"st.d");
}
+TEST_F(AssemblerMIPS64Test, IlvlB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlB, "ilvl.b ${reg1}, ${reg2}, ${reg3}"),
+ "ilvl.b");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvlH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlH, "ilvl.h ${reg1}, ${reg2}, ${reg3}"),
+ "ilvl.h");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvlW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlW, "ilvl.w ${reg1}, ${reg2}, ${reg3}"),
+ "ilvl.w");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvlD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvlD, "ilvl.d ${reg1}, ${reg2}, ${reg3}"),
+ "ilvl.d");
+}
+
TEST_F(AssemblerMIPS64Test, IlvrB) {
DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvrB, "ilvr.b ${reg1}, ${reg2}, ${reg3}"),
"ilvr.b");
@@ -3489,6 +3564,46 @@ TEST_F(AssemblerMIPS64Test, IlvrD) {
"ilvr.d");
}
+TEST_F(AssemblerMIPS64Test, IlvevB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevB, "ilvev.b ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.b");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvevH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevH, "ilvev.h ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.h");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvevW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevW, "ilvev.w ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.w");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvevD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvevD, "ilvev.d ${reg1}, ${reg2}, ${reg3}"),
+ "ilvev.d");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvodB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodB, "ilvod.b ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.b");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvodH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodH, "ilvod.h ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.h");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvodW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodW, "ilvod.w ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.w");
+}
+
+TEST_F(AssemblerMIPS64Test, IlvodD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::IlvodD, "ilvod.d ${reg1}, ${reg2}, ${reg3}"),
+ "ilvod.d");
+}
+
TEST_F(AssemblerMIPS64Test, MaddvB) {
DriverStr(RepeatVVV(&mips64::Mips64Assembler::MaddvB, "maddv.b ${reg1}, ${reg2}, ${reg3}"),
"maddv.b");
@@ -3509,6 +3624,36 @@ TEST_F(AssemblerMIPS64Test, MaddvD) {
"maddv.d");
}
+TEST_F(AssemblerMIPS64Test, Hadd_sH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_sH, "hadd_s.h ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_s.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Hadd_sW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_sW, "hadd_s.w ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Hadd_sD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_sD, "hadd_s.d ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Hadd_uH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_uH, "hadd_u.h ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_u.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Hadd_uW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_uW, "hadd_u.w ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_u.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Hadd_uD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Hadd_uD, "hadd_u.d ${reg1}, ${reg2}, ${reg3}"),
+ "hadd_u.d");
+}
+
TEST_F(AssemblerMIPS64Test, MsubvB) {
DriverStr(RepeatVVV(&mips64::Mips64Assembler::MsubvB, "msubv.b ${reg1}, ${reg2}, ${reg3}"),
"msubv.b");