Restrict some multiply instructions element sizes (#121)
Some Neon instructions such as sqrdmulh only operate on H and S-sized elements.
The disassembler already restricts this, so extend checks to the simulator.
Additionally, reuse the new register/index extraction function in other parts of
the simulator.
diff --git a/src/aarch64/decoder-visitor-map-aarch64.h b/src/aarch64/decoder-visitor-map-aarch64.h
index b4b39f5..b5358ce 100644
--- a/src/aarch64/decoder-visitor-map-aarch64.h
+++ b/src/aarch64/decoder-visitor-map-aarch64.h
@@ -2849,22 +2849,6 @@
&VISITORCLASS::VisitNEONScalarByIndexedElement}, \
{"sqdmull_asisdelem_l"_h, \
&VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmla_asisdelem_rh_h"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmla_asisdelem_r_sd"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmls_asisdelem_rh_h"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmls_asisdelem_r_sd"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmulx_asisdelem_rh_h"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmulx_asisdelem_r_sd"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmul_asisdelem_rh_h"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
- {"fmul_asisdelem_r_sd"_h, \
- &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
{"fabd_asisdsame_only"_h, &VISITORCLASS::VisitNEONScalar3Same}, \
{"facge_asisdsame_only"_h, &VISITORCLASS::VisitNEONScalar3Same}, \
{"facgt_asisdsame_only"_h, &VISITORCLASS::VisitNEONScalar3Same}, \
@@ -2937,6 +2921,22 @@
{"frecpe_asisdmisc_r"_h, &VISITORCLASS::VisitNEONScalar2RegMisc}, \
{"frecpx_asisdmisc_r"_h, &VISITORCLASS::VisitNEONScalar2RegMisc}, \
{"frsqrte_asisdmisc_r"_h, &VISITORCLASS::VisitNEONScalar2RegMisc}, \
- {"scvtf_asisdmisc_r"_h, &VISITORCLASS::VisitNEONScalar2RegMisc}, { \
- "ucvtf_asisdmisc_r"_h, &VISITORCLASS::VisitNEONScalar2RegMisc \
+ {"scvtf_asisdmisc_r"_h, &VISITORCLASS::VisitNEONScalar2RegMisc}, \
+ {"ucvtf_asisdmisc_r"_h, &VISITORCLASS::VisitNEONScalar2RegMisc}, \
+ {"fmla_asisdelem_rh_h"_h, \
+ &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
+ {"fmla_asisdelem_r_sd"_h, \
+ &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
+ {"fmls_asisdelem_rh_h"_h, \
+ &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
+ {"fmls_asisdelem_r_sd"_h, \
+ &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
+ {"fmulx_asisdelem_rh_h"_h, \
+ &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
+ {"fmulx_asisdelem_r_sd"_h, \
+ &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
+ {"fmul_asisdelem_rh_h"_h, \
+ &VISITORCLASS::VisitNEONScalarByIndexedElement}, \
+ { \
+ "fmul_asisdelem_r_sd"_h, &VISITORCLASS::VisitNEONScalarByIndexedElement \
}
diff --git a/src/aarch64/instructions-aarch64.cc b/src/aarch64/instructions-aarch64.cc
index 2ac3bca..a37be34 100644
--- a/src/aarch64/instructions-aarch64.cc
+++ b/src/aarch64/instructions-aarch64.cc
@@ -603,6 +603,28 @@
return std::make_pair(reg_code, index);
}
+// Get the register and index for NEON indexed multiplies.
+std::pair<int, int> Instruction::GetNEONMulRmAndIndex() const {
+ int reg_code = GetRm();
+ int index = (GetNEONH() << 2) | (GetNEONL() << 1) | GetNEONM();
+ switch (GetNEONSize()) {
+ case 0: // FP H-sized elements.
+ case 1: // Integer H-sized elements.
+ // 4-bit Rm, 3-bit index.
+ reg_code &= 0xf;
+ break;
+ case 2: // S-sized elements.
+ // 5-bit Rm, 2-bit index.
+ index >>= 1;
+ break;
+ case 3: // FP D-sized elements.
+ // 5-bit Rm, 1-bit index.
+ index >>= 2;
+ break;
+ }
+ return std::make_pair(reg_code, index);
+}
+
// Logical immediates can't encode zero, so a return value of zero is used to
// indicate a failure case. Specifically, where the constraints on imm_s are
// not met.
diff --git a/src/aarch64/instructions-aarch64.h b/src/aarch64/instructions-aarch64.h
index ce08ea3..ad0ba58 100644
--- a/src/aarch64/instructions-aarch64.h
+++ b/src/aarch64/instructions-aarch64.h
@@ -373,6 +373,7 @@
std::pair<int, int> GetSVEPermuteIndexAndLaneSizeLog2() const;
+ std::pair<int, int> GetNEONMulRmAndIndex() const;
std::pair<int, int> GetSVEMulZmAndIndex() const;
std::pair<int, int> GetSVEMulLongZmAndIndex() const;
diff --git a/src/aarch64/simulator-aarch64.cc b/src/aarch64/simulator-aarch64.cc
index a38e973..070e630 100644
--- a/src/aarch64/simulator-aarch64.cc
+++ b/src/aarch64/simulator-aarch64.cc
@@ -8391,22 +8391,14 @@
void Simulator::SimulateNEONMulByElementLong(const Instruction* instr) {
NEONFormatDecoder nfd(instr);
VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
-
SimVRegister& rd = ReadVRegister(instr->GetRd());
SimVRegister& rn = ReadVRegister(instr->GetRn());
- int rm_reg = instr->GetRm();
- int index = (instr->GetNEONH() << 1) | instr->GetNEONL();
- if (instr->GetNEONSize() == 1) {
- rm_reg = instr->GetRmLow16();
- index = (index << 1) | instr->GetNEONM();
- }
- SimVRegister& rm = ReadVRegister(rm_reg);
-
+ std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
SimVRegister temp;
VectorFormat indexform =
VectorFormatHalfWidthDoubleLanes(VectorFormatFillQ(vf));
- dup_element(indexform, temp, rm, index);
+ dup_elements_to_segments(indexform, temp, rm_and_index);
bool is_2 = instr->Mask(NEON_Q) ? true : false;
@@ -8480,21 +8472,9 @@
SimVRegister& rd = ReadVRegister(instr->GetRd());
SimVRegister& rn = ReadVRegister(instr->GetRn());
- int rm_reg = instr->GetRm();
- int index =
- (instr->GetNEONH() << 2) | (instr->GetNEONL() << 1) | instr->GetNEONM();
-
- if ((vform == kFormat4H) || (vform == kFormat8H)) {
- rm_reg &= 0xf;
- } else if ((vform == kFormat2S) || (vform == kFormat4S)) {
- index >>= 1;
- } else {
- VIXL_ASSERT(vform == kFormat2D);
- VIXL_ASSERT(instr->GetNEONL() == 0);
- index >>= 2;
- }
-
- SimVRegister& rm = ReadVRegister(rm_reg);
+ std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
+ SimVRegister& rm = ReadVRegister(rm_and_index.first);
+ int index = rm_and_index.second;
switch (form_hash_) {
case "fmul_asimdelem_rh_h"_h:
@@ -8574,15 +8554,9 @@
SimVRegister& rd = ReadVRegister(instr->GetRd());
SimVRegister& rn = ReadVRegister(instr->GetRn());
- int rm_reg = instr->GetRm();
- int index = (instr->GetNEONH() << 1) | instr->GetNEONL();
-
- if ((vform == kFormat4H) || (vform == kFormat8H)) {
- rm_reg &= 0xf;
- index = (index << 1) | instr->GetNEONM();
- }
-
- SimVRegister& rm = ReadVRegister(rm_reg);
+ std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
+ SimVRegister& rm = ReadVRegister(rm_and_index.first);
+ int index = rm_and_index.second;
switch (form_hash_) {
case "mul_asimdelem_r"_h:
@@ -9641,78 +9615,76 @@
void Simulator::VisitNEONScalarByIndexedElement(const Instruction* instr) {
NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
VectorFormat vf = nfd.GetVectorFormat();
- VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap());
-
SimVRegister& rd = ReadVRegister(instr->GetRd());
SimVRegister& rn = ReadVRegister(instr->GetRn());
ByElementOp Op = NULL;
- int rm_reg = instr->GetRm();
- int index = (instr->GetNEONH() << 1) | instr->GetNEONL();
- if (instr->GetNEONSize() == 1) {
- rm_reg &= 0xf;
- index = (index << 1) | instr->GetNEONM();
+ std::pair<int, int> rm_and_index = instr->GetNEONMulRmAndIndex();
+ std::unordered_map<uint32_t, ByElementOp> handler = {
+ {"sqdmull_asisdelem_l"_h, &Simulator::sqdmull},
+ {"sqdmlal_asisdelem_l"_h, &Simulator::sqdmlal},
+ {"sqdmlsl_asisdelem_l"_h, &Simulator::sqdmlsl},
+ {"sqdmulh_asisdelem_r"_h, &Simulator::sqdmulh},
+ {"sqrdmulh_asisdelem_r"_h, &Simulator::sqrdmulh},
+ {"sqrdmlah_asisdelem_r"_h, &Simulator::sqrdmlah},
+ {"sqrdmlsh_asisdelem_r"_h, &Simulator::sqrdmlsh},
+ {"fmul_asisdelem_rh_h"_h, &Simulator::fmul},
+ {"fmul_asisdelem_r_sd"_h, &Simulator::fmul},
+ {"fmla_asisdelem_rh_h"_h, &Simulator::fmla},
+ {"fmla_asisdelem_r_sd"_h, &Simulator::fmla},
+ {"fmls_asisdelem_rh_h"_h, &Simulator::fmls},
+ {"fmls_asisdelem_r_sd"_h, &Simulator::fmls},
+ {"fmulx_asisdelem_rh_h"_h, &Simulator::fmulx},
+ {"fmulx_asisdelem_r_sd"_h, &Simulator::fmulx},
+ };
+
+ std::unordered_map<uint32_t, ByElementOp>::const_iterator it =
+ handler.find(form_hash_);
+
+ if (it == handler.end()) {
+ VIXL_UNIMPLEMENTED();
+ } else {
+ Op = it->second;
}
- switch (instr->Mask(NEONScalarByIndexedElementMask)) {
- case NEON_SQDMULL_byelement_scalar:
- Op = &Simulator::sqdmull;
+ switch (form_hash_) {
+ case "sqdmull_asisdelem_l"_h:
+ case "sqdmlal_asisdelem_l"_h:
+ case "sqdmlsl_asisdelem_l"_h:
+ if ((vf == kFormatB) || (vf == kFormatH)) {
+ VisitUnallocated(instr);
+ return;
+ }
break;
- case NEON_SQDMLAL_byelement_scalar:
- Op = &Simulator::sqdmlal;
+ case "sqdmulh_asisdelem_r"_h:
+ case "sqrdmulh_asisdelem_r"_h:
+ case "sqrdmlah_asisdelem_r"_h:
+ case "sqrdmlsh_asisdelem_r"_h:
+ vf = nfd.GetVectorFormat(nfd.ScalarFormatMap());
+ if ((vf == kFormatB) || (vf == kFormatD)) {
+ VisitUnallocated(instr);
+ return;
+ }
break;
- case NEON_SQDMLSL_byelement_scalar:
- Op = &Simulator::sqdmlsl;
- break;
- case NEON_SQDMULH_byelement_scalar:
- Op = &Simulator::sqdmulh;
- vf = vf_r;
- break;
- case NEON_SQRDMULH_byelement_scalar:
- Op = &Simulator::sqrdmulh;
- vf = vf_r;
- break;
- case NEON_SQRDMLAH_byelement_scalar:
- Op = &Simulator::sqrdmlah;
- vf = vf_r;
- break;
- case NEON_SQRDMLSH_byelement_scalar:
- Op = &Simulator::sqrdmlsh;
- vf = vf_r;
- break;
- default:
+ case "fmul_asisdelem_r_sd"_h:
+ case "fmla_asisdelem_r_sd"_h:
+ case "fmls_asisdelem_r_sd"_h:
+ case "fmulx_asisdelem_r_sd"_h:
vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
- index = instr->GetNEONH();
- if (instr->GetFPType() == 0) {
- index = (index << 2) | (instr->GetNEONL() << 1) | instr->GetNEONM();
- rm_reg &= 0xf;
- vf = kFormatH;
- } else if ((instr->GetFPType() & 1) == 0) {
- index = (index << 1) | instr->GetNEONL();
- }
- switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
- case NEON_FMUL_H_byelement_scalar:
- case NEON_FMUL_byelement_scalar:
- Op = &Simulator::fmul;
- break;
- case NEON_FMLA_H_byelement_scalar:
- case NEON_FMLA_byelement_scalar:
- Op = &Simulator::fmla;
- break;
- case NEON_FMLS_H_byelement_scalar:
- case NEON_FMLS_byelement_scalar:
- Op = &Simulator::fmls;
- break;
- case NEON_FMULX_H_byelement_scalar:
- case NEON_FMULX_byelement_scalar:
- Op = &Simulator::fmulx;
- break;
- default:
- VIXL_UNIMPLEMENTED();
- }
+ break;
+ case "fmul_asisdelem_rh_h"_h:
+ case "fmla_asisdelem_rh_h"_h:
+ case "fmls_asisdelem_rh_h"_h:
+ case "fmulx_asisdelem_rh_h"_h:
+ vf = kFormatH;
+ break;
}
- (this->*Op)(vf, rd, rn, ReadVRegister(rm_reg), index);
+ (this->*Op)(vf,
+ rd,
+ rn,
+ ReadVRegister(rm_and_index.first),
+ rm_and_index.second);
}