ArmEmitter: Adds three more classes of ASIMD instructions

Adds three classes:
- Advanced SIMD three same (FP16)
- Advanced SIMD two-register miscellaneous (FP16)
- Advanced SIMD three-register extension

A handful of the three-register extension unit tests are disabled
because the vixl disassembler doesn't support them.

Only six more classes of ASIMD operations remaining once this is merged.
This commit is contained in:
Ryan Houdek committed 2023-01-12 13:38:48 -08:00
1 parent 1521e0a248
commit d787a38744
3 files changed
+632 -6

No files matched your search

@@ -335,6 +335,59 @@ public:
ASIMDScalarCopy(Op, Q, imm5, 0b0000, rd.V(), rn.V());
}
// Advanced SIMD three same (FP16)
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void ASIMDThreeSameFP16(uint32_t U, uint32_t a, uint32_t opcode, T rm, T rn, T rd) {
constexpr uint32_t Q = std::is_same_v<FEXCore::ARMEmitter::QRegister, T> ? 1U << 30 : 0;
constexpr uint32_t Op = 0b0000'1110'0100'0000'0000'01 << 10;
uint32_t Instr = Op;
Instr |= Q;
Instr |= U << 29;
Instr |= a << 23;
Instr |= rm.Idx() << 16;
Instr |= opcode << 11;
Instr |= rn.Idx() << 5;
Instr |= rd.Idx();
dc32(Instr);
}
// Advanced SIMD two-register miscellaneous (FP16)
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void ASIMDTwoRegMiscFP16(uint32_t U, uint32_t a, uint32_t opcode, T rn, T rd) {
constexpr uint32_t Q = std::is_same_v<FEXCore::ARMEmitter::QRegister, T> ? 1U << 30 : 0;
constexpr uint32_t Op = 0b0000'1110'0111'1000'0000'10 << 10;
uint32_t Instr = Op;
Instr |= Q;
Instr |= U << 29;
Instr |= a << 23;
Instr |= opcode << 12;
Instr |= rn.Idx() << 5;
Instr |= rd.Idx();
dc32(Instr);
}
// Advanced SIMD three-register extension
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void ASIMDThreeRegisterExt(uint32_t U, uint32_t opcode, FEXCore::ARMEmitter::SubRegSize size, T rm, T rn, T rd) {
constexpr uint32_t Q = std::is_same_v<FEXCore::ARMEmitter::QRegister, T> ? 1U << 30 : 0;
constexpr uint32_t Op = 0b0000'1110'0000'0000'1000'01 << 10;
uint32_t Instr = Op;
Instr |= Q;
Instr |= U << 29;
Instr |= FEXCore::ToUnderlying(size) << 22;
Instr |= rm.Idx() << 16;
Instr |= opcode << 11;
Instr |= rn.Idx() << 5;
Instr |= rd.Idx();
dc32(Instr);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void dup(FEXCore::ARMEmitter::SubRegSize size, T rd, FEXCore::ARMEmitter::Register rn) {
@@ -532,11 +585,420 @@ public:
// Advanced SIMD three same (FP16)
// TODO
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmaxnm(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 0, 0b000, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmla(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 0, 0b001, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fadd(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 0, 0b010, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmulx(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 0, 0b011, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmeq(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 0, 0b100, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmax(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 0, 0b110, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frecps(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 0, 0b111, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fminnm(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 1, 0b000, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmls(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 1, 0b001, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fsub(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 1, 0b010, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmin(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 1, 0b110, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frsqrts(T rd, T rn, T rm) {
ASIMDThreeSameFP16(0, 1, 0b111, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmaxnmp(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 0, 0b000, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void faddp(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 0, 0b010, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmul(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 0, 0b011, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmge(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 0, 0b100, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void facge(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 0, 0b101, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fmaxp(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 0, 0b110, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fdiv(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 0, 0b111, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fminnmp(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 1, 0b000, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fabd(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 1, 0b010, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmgt(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 1, 0b100, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void facgt(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 1, 0b101, rm, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fminp(T rd, T rn, T rm) {
ASIMDThreeSameFP16(1, 1, 0b110, rm, rn, rd);
}
// Advanced SIMD two-register miscellaneous (FP16)
// TODO
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frintn(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 0, 0b11000, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frintm(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 0, 0b11001, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtns(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 0, 0b11010, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtms(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 0, 0b11011, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtas(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 0, 0b11100, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void scvtf(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 0, 0b11101, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmgt(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b01100, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmeq(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b01101, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmlt(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b01110, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fabs(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b01111, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frintp(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b11000, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frintz(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b11001, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtps(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b11010, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtzs(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b11011, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frecpe(T rd, T rn) {
ASIMDTwoRegMiscFP16(0, 1, 0b11101, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frinta(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 0, 0b11000, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frintx(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 0, 0b11001, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtnu(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 0, 0b11010, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtmu(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 0, 0b11011, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtau(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 0, 0b11100, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void ucvtf(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 0, 0b11101, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmge(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b01100, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcmle(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b01101, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fneg(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b01111, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frinti(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b11001, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtpu(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b11010, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fcvtzu(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b11011, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void frsqrte(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b11101, rn, rd);
}
template<FEXCore::ARMEmitter::SubRegSize size, typename T>
requires(size == FEXCore::ARMEmitter::SubRegSize::i16Bit &&
(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>))
void fsqrt(T rd, T rn) {
ASIMDTwoRegMiscFP16(1, 1, 0b11111, rn, rd);
}
// Advanced SIMD three-register extension
// TODO
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void sdot(FEXCore::ARMEmitter::SubRegSize size, T rd, T rn, T rm) {
if constexpr (std::is_same_v<FEXCore::ARMEmitter::DRegister, T>) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i64Bit, "64-bit subregsize not supported");
}
ASIMDThreeRegisterExt(0, 0b0010, size, rm, rn, rd);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void usdot(T rd, T rn, T rm) {
ASIMDThreeRegisterExt(0, 0b0011, FEXCore::ARMEmitter::SubRegSize::i32Bit, rm, rn, rd);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void sqrdmlah(FEXCore::ARMEmitter::SubRegSize size, T rd, T rn, T rm) {
if constexpr (std::is_same_v<FEXCore::ARMEmitter::DRegister, T>) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i64Bit, "64-bit subregsize not supported");
}
ASIMDThreeRegisterExt(1, 0b0000, size, rm, rn, rd);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void sqrdmlsh(FEXCore::ARMEmitter::SubRegSize size, T rd, T rn, T rm) {
if constexpr (std::is_same_v<FEXCore::ARMEmitter::DRegister, T>) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i64Bit, "64-bit subregsize not supported");
}
ASIMDThreeRegisterExt(1, 0b0001, size, rm, rn, rd);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void udot(FEXCore::ARMEmitter::SubRegSize size, T rd, T rn, T rm) {
if constexpr (std::is_same_v<FEXCore::ARMEmitter::DRegister, T>) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i64Bit, "64-bit subregsize not supported");
}
ASIMDThreeRegisterExt(1, 0b0010, size, rm, rn, rd);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void fcmla(FEXCore::ARMEmitter::SubRegSize size, T rd, T rn, T rm, FEXCore::ARMEmitter::Rotation Rot) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i8Bit, "8-bit subregsize not supported");
if constexpr (std::is_same_v<FEXCore::ARMEmitter::DRegister, T>) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i64Bit, "64-bit subregsize not supported");
}
ASIMDThreeRegisterExt(1, 0b1000 | FEXCore::ToUnderlying(Rot), size, rm, rn, rd);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void fcadd(FEXCore::ARMEmitter::SubRegSize size, T rd, T rn, T rm, FEXCore::ARMEmitter::Rotation Rot) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i8Bit, "8-bit subregsize not supported");
if constexpr (std::is_same_v<FEXCore::ARMEmitter::DRegister, T>) {
LOGMAN_THROW_AA_FMT(size != FEXCore::ARMEmitter::SubRegSize::i64Bit, "64-bit subregsize not supported");
}
LOGMAN_THROW_A_FMT(Rot == FEXCore::ARMEmitter::Rotation::ROTATE_90 || Rot == FEXCore::ARMEmitter::Rotation::ROTATE_270, "Invalid rotation");
const uint32_t ConvertedRotation =
Rot == FEXCore::ARMEmitter::Rotation::ROTATE_90 ? 0b00 : 0b10;
ASIMDThreeRegisterExt(1, 0b1100 | ConvertedRotation, size, rm, rn, rd);
}
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
void bfdot(T rd, T rn, T rm) {
ASIMDThreeRegisterExt(1, 0b1111, FEXCore::ARMEmitter::SubRegSize::i16Bit, rm, rn, rd);
}
void bfmlalb(ARMEmitter::VRegister rd, ARMEmitter::VRegister rn, ARMEmitter::VRegister rm) {
ASIMDThreeRegisterExt(1, 0b1111, FEXCore::ARMEmitter::SubRegSize::i64Bit, rm.D(), rn.D(), rd.D());
}
void bfmlalt(ARMEmitter::VRegister rd, ARMEmitter::VRegister rn, ARMEmitter::VRegister rm) {
ASIMDThreeRegisterExt(1, 0b1111, FEXCore::ARMEmitter::SubRegSize::i64Bit, rm.Q(), rn.Q(), rd.Q());
}
void smmla(ARMEmitter::VRegister rd, ARMEmitter::VRegister rn, ARMEmitter::VRegister rm) {
ASIMDThreeRegisterExt(0, 0b0100, FEXCore::ARMEmitter::SubRegSize::i32Bit, rm.Q(), rn.Q(), rd.Q());
}
void usmmla(ARMEmitter::VRegister rd, ARMEmitter::VRegister rn, ARMEmitter::VRegister rm) {
ASIMDThreeRegisterExt(0, 0b0101, FEXCore::ARMEmitter::SubRegSize::i32Bit, rm.Q(), rn.Q(), rd.Q());
}
void bfmmla(ARMEmitter::VRegister rd, ARMEmitter::VRegister rn, ARMEmitter::VRegister rm) {
ASIMDThreeRegisterExt(1, 0b1101, FEXCore::ARMEmitter::SubRegSize::i16Bit, rm.Q(), rn.Q(), rd.Q());
}
void ummla(ARMEmitter::VRegister rd, ARMEmitter::VRegister rn, ARMEmitter::VRegister rm) {
ASIMDThreeRegisterExt(1, 0b0100, FEXCore::ARMEmitter::SubRegSize::i32Bit, rm.Q(), rn.Q(), rd.Q());
}
// Advanced SIMD two-register miscellaneous
template<typename T>
requires(std::is_same_v<FEXCore::ARMEmitter::QRegister, T> || std::is_same_v<FEXCore::ARMEmitter::DRegister, T>)
@@ -535,6 +535,14 @@ namespace FEXCore::ARMEmitter {
ForwardLabel Forward;
};
// Some FCMA ASIMD instructions support a rotation argument.
enum class Rotation : uint32_t {
ROTATE_0 = 0b00,
ROTATE_90 = 0b01,
ROTATE_180 = 0b10,
ROTATE_270 = 0b11,
};
// This is an emitter that is designed around the smallest code bloat as possible.
// Eschewing most developer convenience in order to keep code as small as possible.
+159 -3
View File
@@ -249,13 +249,169 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD copy") {
TEST_SINGLE(ins(SubRegSize::i64Bit, VReg::v30, 1, VReg::v29, 0), "mov v30.d[1], v29.d[0]");
}
TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three same (FP16)") {
// TODO: Implement in emitter.
TEST_SINGLE(fmaxnm<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmaxnm v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmla<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmla v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fadd<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fadd v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmulx<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmulx v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fcmeq<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fcmeq v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmax<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmax v30.8h, v29.8h, v28.8h");
TEST_SINGLE(frecps<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "frecps v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fminnm<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fminnm v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmls<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmls v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fsub<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fsub v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmin<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmin v30.8h, v29.8h, v28.8h");
TEST_SINGLE(frsqrts<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "frsqrts v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmaxnmp<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmaxnmp v30.8h, v29.8h, v28.8h");
TEST_SINGLE(faddp<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "faddp v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmul<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmul v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fcmge<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fcmge v30.8h, v29.8h, v28.8h");
TEST_SINGLE(facge<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "facge v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fmaxp<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fmaxp v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fdiv<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fdiv v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fminnmp<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fminnmp v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fabd<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fabd v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fcmgt<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fcmgt v30.8h, v29.8h, v28.8h");
TEST_SINGLE(facgt<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "facgt v30.8h, v29.8h, v28.8h");
TEST_SINGLE(fminp<SubRegSize::i16Bit>(QReg::q30, QReg::q29, QReg::q28), "fminp v30.8h, v29.8h, v28.8h");
}
TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register miscellaneous (FP16)") {
// TODO: Implement in emitter.
TEST_SINGLE(frintn<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frintn v30.8h, v29.8h");
TEST_SINGLE(frintm<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frintm v30.8h, v29.8h");
TEST_SINGLE(fcvtns<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtns v30.8h, v29.8h");
TEST_SINGLE(fcvtms<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtms v30.8h, v29.8h");
TEST_SINGLE(fcvtas<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtas v30.8h, v29.8h");
TEST_SINGLE(scvtf<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "scvtf v30.8h, v29.8h");
TEST_SINGLE(fcmgt<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcmgt v30.8h, v29.8h, #0.0");
TEST_SINGLE(fcmeq<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcmeq v30.8h, v29.8h, #0.0");
TEST_SINGLE(fcmlt<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcmlt v30.8h, v29.8h, #0.0");
TEST_SINGLE(fabs<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fabs v30.8h, v29.8h");
TEST_SINGLE(frintp<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frintp v30.8h, v29.8h");
TEST_SINGLE(frintz<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frintz v30.8h, v29.8h");
TEST_SINGLE(fcvtps<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtps v30.8h, v29.8h");
TEST_SINGLE(fcvtzs<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtzs v30.8h, v29.8h");
TEST_SINGLE(frecpe<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frecpe v30.8h, v29.8h");
TEST_SINGLE(frinta<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frinta v30.8h, v29.8h");
TEST_SINGLE(frintx<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frintx v30.8h, v29.8h");
TEST_SINGLE(fcvtnu<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtnu v30.8h, v29.8h");
TEST_SINGLE(fcvtmu<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtmu v30.8h, v29.8h");
TEST_SINGLE(fcvtau<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtau v30.8h, v29.8h");
TEST_SINGLE(ucvtf<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "ucvtf v30.8h, v29.8h");
TEST_SINGLE(fcmge<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcmge v30.8h, v29.8h, #0.0");
TEST_SINGLE(fcmle<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcmle v30.8h, v29.8h, #0.0");
TEST_SINGLE(fneg<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fneg v30.8h, v29.8h");
TEST_SINGLE(frinti<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frinti v30.8h, v29.8h");
TEST_SINGLE(fcvtpu<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtpu v30.8h, v29.8h");
TEST_SINGLE(fcvtzu<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fcvtzu v30.8h, v29.8h");
TEST_SINGLE(frsqrte<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "frsqrte v30.8h, v29.8h");
TEST_SINGLE(fsqrt<SubRegSize::i16Bit>(QReg::q30, QReg::q29), "fsqrt v30.8h, v29.8h");
}
TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD three-register extension") {
// TODO: Implement in emitter.
TEST_SINGLE(sdot(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sdot v30.16b, v29.16b, v28.16b");
TEST_SINGLE(sdot(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sdot v30.8h, v29.16b, v28.16b");
TEST_SINGLE(sdot(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sdot v30.4s, v29.16b, v28.16b");
TEST_SINGLE(sdot(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sdot v30.2d, v29.16b, v28.16b");
TEST_SINGLE(sdot(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.8b, v29.8b, v28.8b");
TEST_SINGLE(sdot(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.4h, v29.8b, v28.8b");
TEST_SINGLE(sdot(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.2s, v29.8b, v28.8b");
//TEST_SINGLE(sdot(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sdot v30.1d, v29.8b, v28.8b");
TEST_SINGLE(usdot(QReg::q30, QReg::q29, QReg::q28), "usdot v30.4s, v29.16b, v28.16b");
TEST_SINGLE(usdot(DReg::d30, DReg::d29, DReg::d28), "usdot v30.2s, v29.8b, v28.8b");
TEST_SINGLE(sqrdmlah(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlah v30.16b, v29.16b, v28.16b");
TEST_SINGLE(sqrdmlah(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlah v30.8h, v29.8h, v28.8h");
TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlah v30.4s, v29.4s, v28.4s");
TEST_SINGLE(sqrdmlah(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlah v30.2d, v29.2d, v28.2d");
TEST_SINGLE(sqrdmlah(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.8b, v29.8b, v28.8b");
TEST_SINGLE(sqrdmlah(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.4h, v29.4h, v28.4h");
TEST_SINGLE(sqrdmlah(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.2s, v29.2s, v28.2s");
//TEST_SINGLE(sqrdmlah(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlah v30.1d, v29.1d, v28.1d");
TEST_SINGLE(sqrdmlsh(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlsh v30.16b, v29.16b, v28.16b");
TEST_SINGLE(sqrdmlsh(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlsh v30.8h, v29.8h, v28.8h");
TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlsh v30.4s, v29.4s, v28.4s");
TEST_SINGLE(sqrdmlsh(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "sqrdmlsh v30.2d, v29.2d, v28.2d");
TEST_SINGLE(sqrdmlsh(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.8b, v29.8b, v28.8b");
TEST_SINGLE(sqrdmlsh(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.4h, v29.4h, v28.4h");
TEST_SINGLE(sqrdmlsh(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.2s, v29.2s, v28.2s");
//TEST_SINGLE(sqrdmlsh(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "sqrdmlsh v30.1d, v29.1d, v28.1d");
TEST_SINGLE(udot(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28), "udot v30.16b, v29.16b, v28.16b");
TEST_SINGLE(udot(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28), "udot v30.8h, v29.16b, v28.16b");
TEST_SINGLE(udot(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28), "udot v30.4s, v29.16b, v28.16b");
TEST_SINGLE(udot(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28), "udot v30.2d, v29.16b, v28.16b");
TEST_SINGLE(udot(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.8b, v29.8b, v28.8b");
TEST_SINGLE(udot(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.4h, v29.8b, v28.8b");
TEST_SINGLE(udot(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.2s, v29.8b, v28.8b");
//TEST_SINGLE(udot(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28), "udot v30.1d, v29.8b, v28.8b");
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.16b, v29.16b, v28.16b, #0");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.8h, v29.8h, v28.8h, #0");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.4s, v29.4s, v28.4s, #0");
TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_0), "fcmla v30.2d, v29.2d, v28.2d, #0");
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.8b, v29.8b, v28.8b, #0");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.4h, v29.4h, v28.4h, #0");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.2s, v29.2s, v28.2s, #0");
//TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_0), "fcmla v30.1d, v29.1d, v28.1d, #0");
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.16b, v29.16b, v28.16b, #90");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.8h, v29.8h, v28.8h, #90");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.4s, v29.4s, v28.4s, #90");
TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcmla v30.2d, v29.2d, v28.2d, #90");
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.8b, v29.8b, v28.8b, #90");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.4h, v29.4h, v28.4h, #90");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.2s, v29.2s, v28.2s, #90");
//TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcmla v30.1d, v29.1d, v28.1d, #90");
// Vixl disassembler has a bug that claims 8-bit fcmla exists
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.16b, v29.16b, v28.16b, #180");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.8h, v29.8h, v28.8h, #180");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.4s, v29.4s, v28.4s, #180");
TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_180), "fcmla v30.2d, v29.2d, v28.2d, #180");
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.8b, v29.8b, v28.8b, #180");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.4h, v29.4h, v28.4h, #180");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.2s, v29.2s, v28.2s, #180");
//TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_180), "fcmla v30.1d, v29.1d, v28.1d, #180");
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.16b, v29.16b, v28.16b, #270");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.8h, v29.8h, v28.8h, #270");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.4s, v29.4s, v28.4s, #270");
TEST_SINGLE(fcmla(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcmla v30.2d, v29.2d, v28.2d, #270");
//TEST_SINGLE(fcmla(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.8b, v29.8b, v28.8b, #270");
TEST_SINGLE(fcmla(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.4h, v29.4h, v28.4h, #270");
TEST_SINGLE(fcmla(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.2s, v29.2s, v28.2s, #270");
//TEST_SINGLE(fcmla(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcmla v30.1d, v29.1d, v28.1d, #270");
// Vixl disassembler has a bug that claims 8-bit fcadd exists
//TEST_SINGLE(fcadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.16b, v29.16b, v28.16b, #90");
TEST_SINGLE(fcadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.8h, v29.8h, v28.8h, #90");
TEST_SINGLE(fcadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.4s, v29.4s, v28.4s, #90");
TEST_SINGLE(fcadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_90), "fcadd v30.2d, v29.2d, v28.2d, #90");
//TEST_SINGLE(fcadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.8b, v29.8b, v28.8b, #90");
TEST_SINGLE(fcadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.4h, v29.4h, v28.4h, #90");
TEST_SINGLE(fcadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.2s, v29.2s, v28.2s, #90");
//TEST_SINGLE(fcadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_90), "fcadd v30.1d, v29.1d, v28.1d, #90");
//TEST_SINGLE(fcadd(SubRegSize::i8Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.16b, v29.16b, v28.16b, #270");
TEST_SINGLE(fcadd(SubRegSize::i16Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.8h, v29.8h, v28.8h, #270");
TEST_SINGLE(fcadd(SubRegSize::i32Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.4s, v29.4s, v28.4s, #270");
TEST_SINGLE(fcadd(SubRegSize::i64Bit, QReg::q30, QReg::q29, QReg::q28, Rotation::ROTATE_270), "fcadd v30.2d, v29.2d, v28.2d, #270");
//TEST_SINGLE(fcadd(SubRegSize::i8Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.8b, v29.8b, v28.8b, #270");
TEST_SINGLE(fcadd(SubRegSize::i16Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.4h, v29.4h, v28.4h, #270");
TEST_SINGLE(fcadd(SubRegSize::i32Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.2s, v29.2s, v28.2s, #270");
//TEST_SINGLE(fcadd(SubRegSize::i64Bit, DReg::d30, DReg::d29, DReg::d28, Rotation::ROTATE_270), "fcadd v30.1d, v29.1d, v28.1d, #270");
// TODO: Enable once vixl disassembler supports these instructions
// TEST_SINGLE(bfdot(QReg::q30, QReg::q29, QReg::q28), "bfdot v30.4s, v29.8h, v28.8h");
// TEST_SINGLE(bfdot(DReg::d30, DReg::d29, DReg::d28), "bfdot v30.2s, v29.4h, v28.4h");
// TEST_SINGLE(bfmlalb(VReg::v30, VReg::v29, VReg::v28), "bfmlalb v30.4s, v29.8h, v28.8h");
// TEST_SINGLE(bfmlalt(VReg::v30, VReg::v29, VReg::v28), "bfmlalt v30.4s, v29.8h, v28.8h");
TEST_SINGLE(smmla(VReg::v30, VReg::v29, VReg::v28), "smmla v30.4s, v29.16b, v28.16b");
TEST_SINGLE(usmmla(VReg::v30, VReg::v29, VReg::v28), "usmmla v30.4s, v29.16b, v28.16b");
// TODO: Enable once vixl disassembler supports these instructions
//TEST_SINGLE(bfmmla(VReg::v30, VReg::v29, VReg::v28), "bfmmla v30.4s, v29.8h, v28.8h");
TEST_SINGLE(ummla(VReg::v30, VReg::v29, VReg::v28), "ummla v30.4s, v29.16b, v28.16b");
}
TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD two-register miscellaneous") {
// Commented out lines showcase unallocated encodings.