Files
FEX-Emu--FEX/CodeEmitter/CodeEmitter/ScalarOps.inl
T
Ryan Houdek d3ab9bdef6 Remove Float16
We aren't using it. We won't be using it. We need unit tests in our
lives if we want this.
2024-05-16 12:06:54 -07:00

1488 lines
61 KiB
C++

// SPDX-License-Identifier: MIT
/* Scalar instruction emitters.
*
* These contain instruction emitters for scalar ASIMD operations explicitly.
* Some of these emitter arguments might seem a bit strange at first glance,
* but is because ARM's instruction encodings for these instructions are a hot mess.
*
* Specifically FP16 was an afterthought for these scalar operations, using a `ScalarRegSize` with
* 16-bit wouldn't encode an FP16 instruction because they are a different instruction class instead.
*
* Most FP16 operations instead have their own freestanding implementation using `HRegister` arguments.
*
* Meanwhile other FP32 and FP64 instructions will use `ScalarRegSize`, supporting both those sizes.
*
* For Scalar integer operations, these instructions will mostly support all `ScalarRegSize` operations.
* Exceptions to this rule will have asserts in the emitter implementation when misused.
*
*/
public:
// Advanced SIMD scalar copy
void dup(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Index) {
constexpr uint32_t Op = 0b0101'1110'0000'0000'0000'01 << 10;
const uint32_t SizeImm = FEXCore::ToUnderlying(size);
const uint32_t IndexShift = SizeImm + 1;
const uint32_t ElementSize = 1U << SizeImm;
const uint32_t MaxIndex = 128U / (ElementSize * 8);
LOGMAN_THROW_AA_FMT(Index < MaxIndex, "Index too large. Index={}, Max Index: {}", Index, MaxIndex);
const uint32_t imm5 = (Index << IndexShift) | ElementSize;
ASIMDScalarCopy(Op, 1, imm5, 0b0000, rd, rn);
}
void mov(ARMEmitter::ScalarRegSize size, ARMEmitter::VRegister rd, ARMEmitter::VRegister rn, uint32_t Index) {
dup(size, rd, rn, Index);
}
// Advanced SIMD scalar three same FP16
void fmulx(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(0, 0, 0b011, rm, rn, rd);
}
void fcmeq(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(0, 0, 0b100, rm, rn, rd);
}
void frecps(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(0, 0, 0b111, rm, rn, rd);
}
void frsqrts(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(0, 1, 0b111, rm, rn, rd);
}
void fcmge(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(1, 0, 0b100, rm, rn, rd);
}
void facge(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(1, 0, 0b101, rm, rn, rd);
}
void fabd(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(1, 1, 0b010, rm, rn, rd);
}
void fcmgt(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(1, 1, 0b100, rm, rn, rd);
}
void facgt(HRegister rd, HRegister rn, HRegister rm) {
ASIMDScalarThreeSameFP16(1, 1, 0b101, rm, rn, rd);
}
// Advanced SIMD scalar two-register miscellaneous FP16
void fcvtns(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 0, 0b11010, rn, rd);
}
void fcvtms(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 0, 0b11011, rn, rd);
}
void fcvtas(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 0, 0b11100, rn, rd);
}
void scvtf(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 0, 0b11101, rn, rd);
}
void fcmgt(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 1, 0b01100, rn, rd);
}
void fcmeq(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 1, 0b01101, rn, rd);
}
void fcmlt(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 1, 0b01110, rn, rd);
}
void fcvtps(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 1, 0b11010, rn, rd);
}
void fcvtzs(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 1, 0b11011, rn, rd);
}
void frecpe(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 1, 0b11101, rn, rd);
}
void frecpx(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(0, 1, 0b11111, rn, rd);
}
void fcvtnu(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 0, 0b11010, rn, rd);
}
void fcvtmu(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 0, 0b11011, rn, rd);
}
void fcvtau(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 0, 0b11100, rn, rd);
}
void ucvtf(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 0, 0b11101, rn, rd);
}
void fcmge(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 1, 0b01100, rn, rd);
}
void fcmle(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 1, 0b01101, rn, rd);
}
void fcvtpu(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 1, 0b11010, rn, rd);
}
void fcvtzu(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 1, 0b11011, rn, rd);
}
void frsqrte(HRegister rd, HRegister rn) {
ASIMDScalarTwoRegMiscFP16(1, 1, 0b11101, rn, rd);
}
// Advanced SIMD scalar three same extra
// XXX:
// Advanced SIMD scalar two-register miscellaneous
void suqadd(ScalarRegSize size, VRegister rd, VRegister rn) {
ASIMDScalar2RegMisc(0, 0, size, 0b00011, rd, rn);
}
void sqabs(ScalarRegSize size, VRegister rd, VRegister rn) {
ASIMDScalar2RegMisc(0, 0, size, 0b00111, rd, rn);
}
///< Comparison against 0.0
void cmgt(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMDScalar2RegMisc(0, 0, size, 0b01000, rd, rn);
}
///< Comparison against 0.0
void cmeq(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMDScalar2RegMisc(0, 0, size, 0b01001, rd, rn);
}
///< Comparison against 0.0
void cmlt(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMDScalar2RegMisc(0, 0, size, 0b01010, rd, rn);
}
void abs(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMDScalar2RegMisc(0, 0, size, 0b01011, rd, rn);
}
///< size is destination size.
void sqxtn(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size != ScalarRegSize::i64Bit, "64-bit destination not supported");
ASIMDScalar2RegMisc(0, 0, size, 0b10100, rd, rn);
}
void fcvtns(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 0, ConvertedSize, 0b11010, rd, rn);
}
void fcvtms(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 0, ConvertedSize, 0b11011, rd, rn);
}
void fcvtas(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 0, ConvertedSize, 0b11100, rd, rn);
}
void scvtf(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 0, ConvertedSize, 0b11101, rd, rn);
}
///< Comparison against 0.0
void fcmgt(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float compare");
ASIMDScalar2RegMisc(0, 0, size, 0b01100, rd, rn);
}
///< Comparison against 0.0
void fcmeq(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float compare");
ASIMDScalar2RegMisc(0, 0, size, 0b01101, rd, rn);
}
///< Comparison against 0.0
void fcmlt(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float compare");
ASIMDScalar2RegMisc(0, 0, size, 0b01110, rd, rn);
}
void fcvtps(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 0, size, 0b11010, rd, rn);
}
void fcvtzs(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 0, size, 0b11011, rd, rn);
}
void frecpe(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 0, size, 0b11101, rd, rn);
}
void frecpx(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 0, size, 0b11111, rd, rn);
}
void usqadd(ScalarRegSize size, VRegister rd, VRegister rn) {
ASIMDScalar2RegMisc(0, 1, size, 0b00011, rd, rn);
}
void sqneg(ScalarRegSize size, VRegister rd, VRegister rn) {
ASIMDScalar2RegMisc(0, 1, size, 0b00111, rd, rn);
}
///< Comparison against 0.0
void cmge(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMDScalar2RegMisc(0, 1, size, 0b01000, rd, rn);
}
///< Comparison against 0.0
void cmle(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMDScalar2RegMisc(0, 1, size, 0b01001, rd, rn);
}
void neg(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMDScalar2RegMisc(0, 1, size, 0b01011, rd, rn);
}
///< size is destination.
void sqxtun(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size != ScalarRegSize::i64Bit, "64-bit destination not supported");
ASIMDScalar2RegMisc(0, 1, size, 0b10010, rd, rn);
}
///< size is destination.
void uqxtn(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size != ScalarRegSize::i64Bit, "64-bit destination not supported");
ASIMDScalar2RegMisc(0, 1, size, 0b10100, rd, rn);
}
///< size is destination.
void fcvtxn(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 1, ScalarRegSize::i16Bit, 0b10110, rd, rn);
}
void fcvtnu(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 1, ConvertedSize, 0b11010, rd, rn);
}
void fcvtmu(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 1, ConvertedSize, 0b11011, rd, rn);
}
void fcvtau(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 1, ConvertedSize, 0b11100, rd, rn);
}
void ucvtf(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(0, 1, ConvertedSize, 0b11101, rd, rn);
}
///< Comparison against 0.0
void fcmge(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 1, size, 0b01100, rd, rn);
}
///< Comparison against 0.0
void fcmle(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 1, size, 0b01101, rd, rn);
}
void fcvtpu(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 1, size, 0b11010, rd, rn);
}
void fcvtzu(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 1, size, 0b11011, rd, rn);
}
void frsqrte(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(0, 1, size, 0b11101, rd, rn);
}
// Advanced SIMD scalar pairwise
void addp(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i64Bit, "Invalid size selected for addp");
ASIMDScalar2RegMisc(1, 0, size, 0b11011, rd, rn);
}
void fmaxnmp(HRegister rd, HRegister rn) {
ASIMDScalar2RegMisc(1, 0, ScalarRegSize::i8Bit, 0b01100, rd.V(), rn.V());
}
void faddp(HRegister rd, HRegister rn) {
ASIMDScalar2RegMisc(1, 0, ScalarRegSize::i8Bit, 0b01101, rd.V(), rn.V());
}
void fmaxp(HRegister rd, HRegister rn) {
ASIMDScalar2RegMisc(1, 0, ScalarRegSize::i8Bit, 0b01111, rd.V(), rn.V());
}
void fminnmp(HRegister rd, HRegister rn) {
ASIMDScalar2RegMisc(1, 0, ScalarRegSize::i32Bit, 0b01100, rd.V(), rn.V());
}
void fminp(HRegister rd, HRegister rn) {
ASIMDScalar2RegMisc(1, 0, ScalarRegSize::i32Bit, 0b01111, rd.V(), rn.V());
}
void fmaxnmp(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(1, 1, ConvertedSize, 0b01100, rd, rn);
}
void faddp(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(1, 1, ConvertedSize, 0b01101, rd, rn);
}
void fmaxp(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMDScalar2RegMisc(1, 1, ConvertedSize, 0b01111, rd, rn);
}
void fminnmp(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(1, 1, size, 0b01100, rd, rn);
}
void fminp(ScalarRegSize size, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMDScalar2RegMisc(1, 1, size, 0b01111, rd, rn);
}
// Advanced SIMD scalar three different
///< size is destination.
void sqdmlal(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i32Bit :
ScalarRegSize::i16Bit;
ASIMD3RegDifferent(0, ConvertedSize, 0b1001, rd, rn, rm);
}
///< size is destination.
void sqdmlsl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i32Bit :
ScalarRegSize::i16Bit;
ASIMD3RegDifferent(0, ConvertedSize, 0b1011, rd, rn, rm);
}
///< size is destination.
void sqdmull(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i32Bit :
ScalarRegSize::i16Bit;
ASIMD3RegDifferent(0, ConvertedSize, 0b1101, rd, rn, rm);
}
// Advanced SIMD scalar three same
void sqadd(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(0, size, 0b00001, rd, rn, rm);
}
void sqsub(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(0, size, 0b00101, rd, rn, rm);
}
void cmgt(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(0, size, 0b00110, rd, rn, rm);
}
void cmge(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(0, size, 0b00111, rd, rn, rm);
}
void sshl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(0, size, 0b01000, rd, rn, rm);
}
void sqshl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(0, size, 0b01001, rd, rn, rm);
}
void srshl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(0, size, 0b01010, rd, rn, rm);
}
void sqrshl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(0, size, 0b01011, rd, rn, rm);
}
void add(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(0, size, 0b10000, rd, rn, rm);
}
void cmtst(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(0, size, 0b10001, rd, rn, rm);
}
void sqdmulh(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i32Bit || size == ScalarRegSize::i16Bit, "Invalid size");
ASIMD3RegSame(0, size, 0b10110, rd, rn, rm);
}
void fmulx(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMD3RegSame(0, ConvertedSize, 0b11011, rd, rn, rm);
}
void fcmeq(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMD3RegSame(0, ConvertedSize, 0b11100, rd, rn, rm);
}
void frecps(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMD3RegSame(0, ConvertedSize, 0b11111, rd, rn, rm);
}
void frsqrts(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMD3RegSame(0, size, 0b11111, rd, rn, rm);
}
void uqadd(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(1, size, 0b00001, rd, rn, rm);
}
void uqsub(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(1, size, 0b00101, rd, rn, rm);
}
void cmhi(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(1, size, 0b00110, rd, rn, rm);
}
void cmhs(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(1, size, 0b00111, rd, rn, rm);
}
void ushl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(1, size, 0b01000, rd, rn, rm);
}
void uqshl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(1, size, 0b01001, rd, rn, rm);
}
void urshl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(1, size, 0b01010, rd, rn, rm);
}
void uqrshl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
ASIMD3RegSame(1, size, 0b01011, rd, rn, rm);
}
void sub(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(1, size, 0b10000, rd, rn, rm);
}
void cmeq(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit, "Only supports 64-bit");
ASIMD3RegSame(1, size, 0b10001, rd, rn, rm);
}
void sqrdmulh(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i32Bit || size == ScalarRegSize::i16Bit, "Invalid size");
ASIMD3RegSame(1, size, 0b10110, rd, rn, rm);
}
void fcmge(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMD3RegSame(1, ConvertedSize, 0b11100, rd, rn, rm);
}
void facge(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
const ScalarRegSize ConvertedSize =
size == ScalarRegSize::i64Bit ?
ScalarRegSize::i16Bit :
ScalarRegSize::i8Bit;
ASIMD3RegSame(1, ConvertedSize, 0b11101, rd, rn, rm);
}
void fabd(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMD3RegSame(1, size, 0b11010, rd, rn, rm);
}
void fcmgt(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMD3RegSame(1, size, 0b11100, rd, rn, rm);
}
void facgt(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for float convert");
ASIMD3RegSame(1, size, 0b11101, rd, rn, rm);
}
// Advanced SIMD scalar shift by immediate
void sshr(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b00000, rd, rn);
}
void ssra(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b00010, rd, rn);
}
void srshr(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b00100, rd, rn);
}
void srsra(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b00110, rd, rn);
}
void shl(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
// Shift encoded a bit weirdly.
// shift = immh:immb - elementsize but immh is /also/ used for element size.
const uint32_t immh = 1 << FEXCore::ToUnderlying(size) | (Shift >> 3);
const uint32_t immb = Shift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b01010, rd, rn);
}
void sqshl(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
// Shift encoded a bit weirdly.
// shift = immh:immb - elementsize but immh is /also/ used for element size.
const uint32_t immh = 1 << FEXCore::ToUnderlying(size) | (Shift >> 3);
const uint32_t immb = Shift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b01110, rd, rn);
}
///< size is destination
void sqshrn(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size != ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sqshrn");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b10010, rd, rn);
}
void sqrshrn(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size != ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sqshrn");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(0, immh, immb, 0b10011, rd, rn);
}
// TODO: SCVTF, FCVTZS
void ushr(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b00000, rd, rn);
}
void usra(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b00010, rd, rn);
}
void urshr(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b00100, rd, rn);
}
void ursra(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b00110, rd, rn);
}
void sri(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b01000, rd, rn);
}
void sli(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_AA_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size == ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sshr");
// Shift encoded a bit weirdly.
// shift = immh:immb - elementsize but immh is /also/ used for element size.
const uint32_t immh = 1 << FEXCore::ToUnderlying(size) | (Shift >> 3);
const uint32_t immb = Shift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b01010, rd, rn);
}
void sqshlu(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
// Shift encoded a bit weirdly.
// shift = immh:immb - elementsize but immh is /also/ used for element size.
const uint32_t immh = 1 << FEXCore::ToUnderlying(size) | (Shift >> 3);
const uint32_t immb = Shift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b01100, rd, rn);
}
void uqshl(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
// Shift encoded a bit weirdly.
// shift = immh:immb - elementsize but immh is /also/ used for element size.
const uint32_t immh = 1 << FEXCore::ToUnderlying(size) | (Shift >> 3);
const uint32_t immb = Shift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b01110, rd, rn);
}
///< size is destination.
void sqshrun(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size != ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sqshrun");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b10000, rd, rn);
}
///< size is destination.
void sqrshrun(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size != ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sqrshrun");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b10001, rd, rn);
}
///< size is destination.
void uqshrn(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size != ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sqrshrun");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b10010, rd, rn);
}
///< size is destination.
void uqrshrn(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Shift) {
LOGMAN_THROW_A_FMT(Shift > 0 && Shift < ScalarRegSizeInBits(size), "Invalid shift for sshr");
LOGMAN_THROW_AA_FMT(size != ARMEmitter::ScalarRegSize::i64Bit, "Invalid size selected for sqrshrun");
const size_t SubregSizeInBits = ScalarRegSizeInBits(size);
// Shift encoded in immh:immb, but inverted with 128-bit source
// shift = (esize * 2) - immh:immb
const uint32_t InvertedShift = (SubregSizeInBits * 2) - Shift;
const uint32_t immh = InvertedShift >> 3;
const uint32_t immb = InvertedShift & 0b111;
ASIMDScalarShiftByImm(1, immh, immb, 0b10011, rd, rn);
}
// TODO: UCVTF, FCVTZU
// Advanced SIMD scalar x indexed element
// XXX:
//
// Floating-point data-processing (1 source)
void fmov(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b000000, rd, rn);
}
void fabs(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b000001, rd, rn);
}
void fneg(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b000010, rd, rn);
}
void fsqrt(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b000011, rd, rn);
}
void frintn(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b001000, rd, rn);
}
void frintp(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b001001, rd, rn);
}
void frintm(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b001010, rd, rn);
}
void frintz(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b001011, rd, rn);
}
void frinta(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b001100, rd, rn);
}
void frintx(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b001110, rd, rn);
}
void frinti(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b001111, rd, rn);
}
void frint32z(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b010000, rd, rn);
}
void frint32x(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b010001, rd, rn);
}
void frint64z(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b010010, rd, rn);
}
void frint64x(ScalarRegSize size, VRegister rd, VRegister rn) {
Float1Source(size, 0, 0, 0b010011, rd, rn);
}
void fmov(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b000000, rd.V(), rn.V());
}
void fabs(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b000001, rd.V(), rn.V());
}
void fneg(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b000010, rd.V(), rn.V());
}
void fsqrt(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b000011, rd.V(), rn.V());
}
void fcvt(DRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b000101, rd.V(), rn.V());
}
void fcvt(HRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b000111, rd.V(), rn.V());
}
void frintn(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b001000, rd.V(), rn.V());
}
void frintp(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b001001, rd.V(), rn.V());
}
void frintm(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b001010, rd.V(), rn.V());
}
void frintz(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b001011, rd.V(), rn.V());
}
void frinta(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b001100, rd.V(), rn.V());
}
void frintx(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b001110, rd.V(), rn.V());
}
void frinti(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b001111, rd.V(), rn.V());
}
void frint32z(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b010000, rd.V(), rn.V());
}
void frint32x(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b010001, rd.V(), rn.V());
}
void frint64z(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b010010, rd.V(), rn.V());
}
void frint64x(SRegister rd, SRegister rn) {
Float1Source(0, 0, 0b00, 0b010011, rd.V(), rn.V());
}
void fmov(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b000000, rd.V(), rn.V());
}
void fabs(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b000001, rd.V(), rn.V());
}
void fneg(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b000010, rd.V(), rn.V());
}
void fsqrt(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b000011, rd.V(), rn.V());
}
void fcvt(SRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b000100, rd.V(), rn.V());
}
void bfcvt(HRegister rd, SRegister rn) {
Float1Source(0, 0, 0b01, 0b000110, rd.V(), rn.V());
}
void fcvt(HRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b000111, rd.V(), rn.V());
}
void frintn(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b001000, rd.V(), rn.V());
}
void frintp(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b001001, rd.V(), rn.V());
}
void frintm(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b001010, rd.V(), rn.V());
}
void frintz(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b001011, rd.V(), rn.V());
}
void frinta(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b001100, rd.V(), rn.V());
}
void frintx(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b001110, rd.V(), rn.V());
}
void frinti(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b001111, rd.V(), rn.V());
}
void frint32z(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b010000, rd.V(), rn.V());
}
void frint32x(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b010001, rd.V(), rn.V());
}
void frint64z(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b010010, rd.V(), rn.V());
}
void frint64x(DRegister rd, DRegister rn) {
Float1Source(0, 0, 0b01, 0b010011, rd.V(), rn.V());
}
void fmov(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b000000, rd.V(), rn.V());
}
void fabs(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b000001, rd.V(), rn.V());
}
void fneg(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b000010, rd.V(), rn.V());
}
void fsqrt(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b000011, rd.V(), rn.V());
}
void fcvt(SRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b000100, rd.V(), rn.V());
}
void fcvt(DRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b000101, rd.V(), rn.V());
}
void frintn(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b001000, rd.V(), rn.V());
}
void frintp(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b001001, rd.V(), rn.V());
}
void frintm(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b001010, rd.V(), rn.V());
}
void frintz(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b001011, rd.V(), rn.V());
}
void frinta(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b001100, rd.V(), rn.V());
}
void frintx(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b001110, rd.V(), rn.V());
}
void frinti(HRegister rd, HRegister rn) {
Float1Source(0, 0, 0b11, 0b001111, rd.V(), rn.V());
}
// Floating-point compare
void fcmp(ScalarRegSize Size, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(Size != ScalarRegSize::i8Bit, "8-bit destination not supported");
const auto ConvertedSize =
Size == ARMEmitter::ScalarRegSize::i64Bit ? 0b01 :
Size == ARMEmitter::ScalarRegSize::i32Bit ? 0b00 :
Size == ARMEmitter::ScalarRegSize::i16Bit ? 0b11 : 0;
FloatCompare(0, 0, ConvertedSize, 0b00, 0b00000, rn, rm);
}
void fcmp(SRegister rn, SRegister rm) {
FloatCompare(0, 0, 0b00, 0b00, 0b00000, rn.V(), rm.V());
}
///< Compare to #0.0
void fcmp(SRegister rn) {
FloatCompare(0, 0, 0b00, 0b00, 0b01000, rn.V(), VReg::v0);
}
void fcmpe(SRegister rn, SRegister rm) {
FloatCompare(0, 0, 0b00, 0b00, 0b10000, rn.V(), rm.V());
}
///< Compare to #0.0
void fcmpe(SRegister rn) {
FloatCompare(0, 0, 0b00, 0b00, 0b11000, rn.V(), VReg::v0);
}
void fcmp(DRegister rn, DRegister rm) {
FloatCompare(0, 0, 0b01, 0b00, 0b00000, rn.V(), rm.V());
}
///< Compare to #0.0
void fcmp(DRegister rn) {
FloatCompare(0, 0, 0b01, 0b00, 0b01000, rn.V(), VReg::v0);
}
void fcmpe(DRegister rn, DRegister rm) {
FloatCompare(0, 0, 0b01, 0b00, 0b10000, rn.V(), rm.V());
}
///< Compare to #0.0
void fcmpe(DRegister rn) {
FloatCompare(0, 0, 0b01, 0b00, 0b11000, rn.V(), VReg::v0);
}
void fcmp(HRegister rn, HRegister rm) {
FloatCompare(0, 0, 0b11, 0b00, 0b00000, rn.V(), rm.V());
}
///< Compare to #0.0
void fcmp(HRegister rn) {
FloatCompare(0, 0, 0b11, 0b00, 0b01000, rn.V(), VReg::v0);
}
void fcmpe(HRegister rn, HRegister rm) {
FloatCompare(0, 0, 0b11, 0b00, 0b10000, rn.V(), rm.V());
}
///< Compare to #0.0
void fcmpe(HRegister rn) {
FloatCompare(0, 0, 0b11, 0b00, 0b11000, rn.V(), VReg::v0);
}
// Floating-point immediate
void fmov(ARMEmitter::ScalarRegSize size, ARMEmitter::VRegister rd, float Value) {
uint32_t M = 0;
uint32_t S = 0;
uint32_t ptype;
uint32_t imm8;
uint32_t imm5 = 0b0'0000;
if (size == ARMEmitter::ScalarRegSize::i16Bit) {
LOGMAN_MSG_A_FMT("Unsupported");
FEX_UNREACHABLE;
}
else if (size == ARMEmitter::ScalarRegSize::i32Bit) {
ptype = 0b00;
imm8 = FP32ToImm8(Value);
}
else if (size == ARMEmitter::ScalarRegSize::i64Bit) {
ptype = 0b01;
imm8 = FP64ToImm8(Value);
}
else {
FEX_UNREACHABLE;
}
FloatScalarImmediate(M, S, ptype, imm8, imm5, rd);
}
void FloatScalarImmediate(uint32_t M, uint32_t S, uint32_t ptype, uint32_t imm8, uint32_t imm5, ARMEmitter::VRegister rd) {
constexpr uint32_t Op = 0b0001'1110'0010'0000'0001'00 << 10;
uint32_t Instr = Op;
Instr |= M << 31;
Instr |= S << 29;
Instr |= ptype << 22;
Instr |= imm8 << 13;
Instr |= imm5 << 5;
Instr |= rd.Idx();
dc32(Instr);
}
// Floating-point conditional compare
void fccmp(SRegister rn, SRegister rm, StatusFlags flags, Condition Cond) {
FloatConditionalCompare(0, 0, 0b00, 0b0, rn.V(), rm.V(), flags, Cond);
}
void fccmpe(SRegister rn, SRegister rm, StatusFlags flags, Condition Cond) {
FloatConditionalCompare(0, 0, 0b00, 0b1, rn.V(), rm.V(), flags, Cond);
}
void fccmp(DRegister rn, DRegister rm, StatusFlags flags, Condition Cond) {
FloatConditionalCompare(0, 0, 0b01, 0b0, rn.V(), rm.V(), flags, Cond);
}
void fccmpe(DRegister rn, DRegister rm, StatusFlags flags, Condition Cond) {
FloatConditionalCompare(0, 0, 0b01, 0b1, rn.V(), rm.V(), flags, Cond);
}
void fccmp(HRegister rn, HRegister rm, StatusFlags flags, Condition Cond) {
FloatConditionalCompare(0, 0, 0b11, 0b0, rn.V(), rm.V(), flags, Cond);
}
void fccmpe(HRegister rn, HRegister rm, StatusFlags flags, Condition Cond) {
FloatConditionalCompare(0, 0, 0b11, 0b1, rn.V(), rm.V(), flags, Cond);
}
// Floating-point data-processing (2 source)
void fmul(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0000, rd, rn, rm);
}
void fdiv(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0001, rd, rn, rm);
}
void fadd(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0010, rd, rn, rm);
}
void fsub(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0011, rd, rn, rm);
}
void fmax(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0100, rd, rn, rm);
}
void fmin(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0101, rd, rn, rm);
}
void fmaxnm(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0110, rd, rn, rm);
}
void fminnm(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b0111, rd, rn, rm);
}
void fnmul(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
Float2Source(size, 0, 0, 0b1000, rd, rn, rm);
}
void fmul(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0000, rd.V(), rn.V(), rm.V());
}
void fdiv(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0001, rd.V(), rn.V(), rm.V());
}
void fadd(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0010, rd.V(), rn.V(), rm.V());
}
void fsub(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0011, rd.V(), rn.V(), rm.V());
}
void fmax(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0100, rd.V(), rn.V(), rm.V());
}
void fmin(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0101, rd.V(), rn.V(), rm.V());
}
void fmaxnm(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0110, rd.V(), rn.V(), rm.V());
}
void fminnm(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b0111, rd.V(), rn.V(), rm.V());
}
void fnmul(SRegister rd, SRegister rn, SRegister rm) {
Float2Source(0, 0, 0b00, 0b1000, rd.V(), rn.V(), rm.V());
}
void fmul(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0000, rd.V(), rn.V(), rm.V());
}
void fdiv(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0001, rd.V(), rn.V(), rm.V());
}
void fadd(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0010, rd.V(), rn.V(), rm.V());
}
void fsub(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0011, rd.V(), rn.V(), rm.V());
}
void fmax(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0100, rd.V(), rn.V(), rm.V());
}
void fmin(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0101, rd.V(), rn.V(), rm.V());
}
void fmaxnm(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0110, rd.V(), rn.V(), rm.V());
}
void fminnm(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b0111, rd.V(), rn.V(), rm.V());
}
void fnmul(DRegister rd, DRegister rn, DRegister rm) {
Float2Source(0, 0, 0b01, 0b1000, rd.V(), rn.V(), rm.V());
}
void fmul(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0000, rd.V(), rn.V(), rm.V());
}
void fdiv(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0001, rd.V(), rn.V(), rm.V());
}
void fadd(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0010, rd.V(), rn.V(), rm.V());
}
void fsub(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0011, rd.V(), rn.V(), rm.V());
}
void fmax(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0100, rd.V(), rn.V(), rm.V());
}
void fmin(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0101, rd.V(), rn.V(), rm.V());
}
void fmaxnm(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0110, rd.V(), rn.V(), rm.V());
}
void fminnm(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b0111, rd.V(), rn.V(), rm.V());
}
void fnmul(HRegister rd, HRegister rn, HRegister rm) {
Float2Source(0, 0, 0b11, 0b1000, rd.V(), rn.V(), rm.V());
}
// Floating-point conditional select
void fcsel(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, Condition Cond) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i16Bit || size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for {}", __func__);
const uint32_t ConvertedSize =
size == ScalarRegSize::i64Bit ? 0b01 :
size == ScalarRegSize::i32Bit ? 0b00 : 0b11;
FloatConditionalSelect(0, 0, ConvertedSize, rd, rn, rm, Cond);
}
void fcsel(SRegister rd, SRegister rn, SRegister rm, Condition Cond) {
FloatConditionalSelect(0, 0, 0b00, rd.V(), rn.V(), rm.V(), Cond);
}
void fcsel(DRegister rd, DRegister rn, DRegister rm, Condition Cond) {
FloatConditionalSelect(0, 0, 0b01, rd.V(), rn.V(), rm.V(), Cond);
}
void fcsel(HRegister rd, HRegister rn, HRegister rm, Condition Cond) {
FloatConditionalSelect(0, 0, 0b11, rd.V(), rn.V(), rm.V(), Cond);
}
// Floating-point data-processing (3 source)
void fmadd(SRegister rd, SRegister rn, SRegister rm, SRegister ra) {
Float3Source(0, 0, 0b00, 0, 0, rd.V(), rn.V(), rm.V(), ra.V());
}
void fmsub(SRegister rd, SRegister rn, SRegister rm, SRegister ra) {
Float3Source(0, 0, 0b00, 0, 1, rd.V(), rn.V(), rm.V(), ra.V());
}
void fnmadd(SRegister rd, SRegister rn, SRegister rm, SRegister ra) {
Float3Source(0, 0, 0b00, 1, 0, rd.V(), rn.V(), rm.V(), ra.V());
}
void fnmsub(SRegister rd, SRegister rn, SRegister rm, SRegister ra) {
Float3Source(0, 0, 0b00, 1, 1, rd.V(), rn.V(), rm.V(), ra.V());
}
void fmadd(DRegister rd, DRegister rn, DRegister rm, DRegister ra) {
Float3Source(0, 0, 0b01, 0, 0, rd.V(), rn.V(), rm.V(), ra.V());
}
void fmsub(DRegister rd, DRegister rn, DRegister rm, DRegister ra) {
Float3Source(0, 0, 0b01, 0, 1, rd.V(), rn.V(), rm.V(), ra.V());
}
void fnmadd(DRegister rd, DRegister rn, DRegister rm, DRegister ra) {
Float3Source(0, 0, 0b01, 1, 0, rd.V(), rn.V(), rm.V(), ra.V());
}
void fnmsub(DRegister rd, DRegister rn, DRegister rm, DRegister ra) {
Float3Source(0, 0, 0b01, 1, 1, rd.V(), rn.V(), rm.V(), ra.V());
}
void fmadd(HRegister rd, HRegister rn, HRegister rm, HRegister ra) {
Float3Source(0, 0, 0b11, 0, 0, rd.V(), rn.V(), rm.V(), ra.V());
}
void fmsub(HRegister rd, HRegister rn, HRegister rm, HRegister ra) {
Float3Source(0, 0, 0b11, 0, 1, rd.V(), rn.V(), rm.V(), ra.V());
}
void fnmadd(HRegister rd, HRegister rn, HRegister rm, HRegister ra) {
Float3Source(0, 0, 0b11, 1, 0, rd.V(), rn.V(), rm.V(), ra.V());
}
void fnmsub(HRegister rd, HRegister rn, HRegister rm, HRegister ra) {
Float3Source(0, 0, 0b11, 1, 1, rd.V(), rn.V(), rm.V(), ra.V());
}
private:
// Advanced SIMD scalar copy
void ASIMDScalarCopy(uint32_t Op, uint32_t Q, uint32_t imm5, uint32_t imm4, ARMEmitter::VRegister rd, ARMEmitter::VRegister rn) {
uint32_t Instr = Op;
Instr |= Q << 30;
Instr |= imm5 << 16;
Instr |= imm4 << 11;
Instr |= Encode_rn(rn);
Instr |= Encode_rd(rd);
dc32(Instr);
}
// Advanced SIMD scalar three same FP16
void ASIMDScalarThreeSameFP16(uint32_t U, uint32_t a, uint32_t opcode, HRegister rm, HRegister rn, HRegister rd) {
uint32_t Instr = 0b0101'1110'0100'0000'0000'0100'0000'0000;
Instr |= U << 29;
Instr |= a << 23;
Instr |= rm.Idx() << 16;
Instr |= opcode << 11;
Instr |= rn.Idx() << 5;
Instr |= rd.Idx();
dc32(Instr);
}
// Advanced SIMD scalar two-register miscellaneous FP16
void ASIMDScalarTwoRegMiscFP16(uint32_t U, uint32_t a, uint32_t opcode, HRegister rn, HRegister rd) {
uint32_t Instr = 0b0101'1110'0111'1000'0000'1000'0000'0000;
Instr |= U << 29;
Instr |= a << 23;
Instr |= opcode << 12;
Instr |= rn.Idx() << 5;
Instr |= rd.Idx();
dc32(Instr);
}
// Advanced SIMD scalar three same extra
// XXX:
// Advanced SIMD scalar two-register miscellaneous
void ASIMDScalar2RegMisc(uint32_t b20, uint32_t U, ScalarRegSize size, uint32_t opcode, VRegister rd, VRegister rn) {
uint32_t Instr = 0b0101'1110'0010'0000'0000'1000'0000'0000;
Instr |= U << 29;
Instr |= FEXCore::ToUnderlying(size) << 22;
Instr |= b20 << 20;
Instr |= opcode << 12;
Instr |= rn.Idx() << 5;
Instr |= rd.Idx();
dc32(Instr);
}
// Advanced SIMD scalar pairwise
// XXX:
// Advanced SIMD scalar three different
void ASIMD3RegDifferent(uint32_t U, ScalarRegSize size, uint32_t opcode, VRegister rd, VRegister rn, VRegister rm) {
uint32_t Instr = 0b0101'1110'0010'0000'0000'0000'0000'0000;
Instr |= U << 29;
Instr |= FEXCore::ToUnderlying(size) << 22;
Instr |= Encode_rm(rm);
Instr |= opcode << 12;
Instr |= Encode_rn(rn);
Instr |= Encode_rd(rd);
dc32(Instr);
}
// Advanced SIMD scalar three same
void ASIMD3RegSame(uint32_t U, ScalarRegSize size, uint32_t opcode, VRegister rd, VRegister rn, VRegister rm) {
uint32_t Instr = 0b0101'1110'0010'0000'0000'0100'0000'0000;
Instr |= U << 29;
Instr |= FEXCore::ToUnderlying(size) << 22;
Instr |= Encode_rm(rm);
Instr |= opcode << 11;
Instr |= Encode_rn(rn);
Instr |= Encode_rd(rd);
dc32(Instr);
}
// Advanced SIMD scalar shift by immediate
void ASIMDScalarShiftByImm(uint32_t U, uint32_t immh, uint32_t immb, uint32_t opcode, VRegister rd, VRegister rn) {
uint32_t Instr = 0b0101'1111'0000'0000'0000'0100'0000'0000;
Instr |= U << 29;
Instr |= immh << 19;
Instr |= immb << 16;
Instr |= opcode << 11;
Instr |= Encode_rn(rn);
Instr |= Encode_rd(rd);
dc32(Instr);
}
// Advanced SIMD scalar x indexed element
// XXX:
// Floating-point data-processing (1 source)
void Float1Source(uint32_t M, uint32_t S, uint32_t ptype, uint32_t opcode, VRegister rd, VRegister rn) {
uint32_t Instr = 0b0001'1110'0010'0000'0100'0000'0000'0000;
Instr |= M << 31;
Instr |= S << 29;
Instr |= ptype << 22;
Instr |= opcode << 15;
Instr |= Encode_rn(rn);
Instr |= Encode_rd(rd);
dc32(Instr);
}
void Float1Source(ScalarRegSize size, uint32_t M, uint32_t S, uint32_t opcode, VRegister rd, VRegister rn) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i16Bit || size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for {}", __func__);
const uint32_t ConvertedSize =
size == ScalarRegSize::i64Bit ? 0b01 :
size == ScalarRegSize::i32Bit ? 0b00 : 0b11;
Float1Source(M, S, ConvertedSize, opcode, rd, rn);
}
// Floating-point compare
void FloatCompare(uint32_t M, uint32_t S, uint32_t ftype, uint32_t op, uint32_t opcode2, VRegister rn, VRegister rm) {
uint32_t Instr = 0b0001'1110'0010'0000'0010'0000'0000'0000;
Instr |= M << 31;
Instr |= S << 29;
Instr |= ftype << 22;
Instr |= Encode_rm(rm);
Instr |= op << 14;
Instr |= Encode_rn(rn);
Instr |= opcode2;
dc32(Instr);
}
// Floating-point immediate
// XXX:
// Floating-point conditional compare
void FloatConditionalCompare(uint32_t M, uint32_t S, uint32_t ptype, uint32_t op, VRegister rn, VRegister rm, StatusFlags flags, Condition Cond) {
uint32_t Instr = 0b0001'1110'0010'0000'0000'0100'0000'0000;
Instr |= M << 31;
Instr |= S << 29;
Instr |= ptype << 22;
Instr |= Encode_rm(rm);
Instr |= FEXCore::ToUnderlying(Cond) << 12;
Instr |= Encode_rn(rn);
Instr |= op << 4;
Instr |= FEXCore::ToUnderlying(flags);
dc32(Instr);
}
// Floating-point data-processing (2 source)
void Float2Source(uint32_t M, uint32_t S, uint32_t ptype, uint32_t opcode, VRegister rd, VRegister rn, VRegister rm) {
uint32_t Instr = 0b0001'1110'0010'0000'0000'1000'0000'0000;
Instr |= M << 31;
Instr |= S << 29;
Instr |= ptype << 22;
Instr |= Encode_rm(rm);
Instr |= opcode << 12;
Instr |= Encode_rn(rn);
Instr |= Encode_rd(rd);
dc32(Instr);
}
void Float2Source(ScalarRegSize size, uint32_t M, uint32_t S, uint32_t opcode, VRegister rd, VRegister rn, VRegister rm) {
LOGMAN_THROW_AA_FMT(size == ScalarRegSize::i16Bit || size == ScalarRegSize::i64Bit || size == ScalarRegSize::i32Bit, "Invalid size selected for {}", __func__);
const uint32_t ConvertedSize =
size == ScalarRegSize::i64Bit ? 0b01 :
size == ScalarRegSize::i32Bit ? 0b00 : 0b11;
Float2Source(M, S, ConvertedSize, opcode, rd, rn, rm);
}
// Floating-point conditional select
void FloatConditionalSelect(uint32_t M, uint32_t S, uint32_t ptype, VRegister rd, VRegister rn, VRegister rm, Condition Cond) {
uint32_t Instr = 0b0001'1110'0010'0000'0000'1100'0000'0000;
Instr |= M << 31;
Instr |= S << 29;
Instr |= ptype << 22;
Instr |= rm.Idx() << 16;
Instr |= FEXCore::ToUnderlying(Cond) << 12;
Instr |= rn.Idx() << 5;
Instr |= rd.Idx();
dc32(Instr);
}
// Floating-point data-processing (3 source)
void Float3Source(uint32_t M, uint32_t S, uint32_t ptype, uint32_t o1, uint32_t o0, VRegister rd, VRegister rn, VRegister rm, VRegister ra) {
uint32_t Instr = 0b0001'1111'0000'0000'0000'0000'0000'0000;
Instr |= M << 31;
Instr |= S << 29;
Instr |= ptype << 22;
Instr |= o1 << 21;
Instr |= Encode_rm(rm);
Instr |= o0 << 15;
Instr |= Encode_ra(ra);
Instr |= Encode_rn(rn);
Instr |= Encode_rd(rd);
dc32(Instr);
}