mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 14:00:16 +02:00
A prevalent pattern in the FEX codebase is to compute some data and store it in a maybe_unused variable that's only ever passed to LOGMAN_THROW_A_FMT. Besides few exceptions, we never compute expensive data in the macro arguments themselves, so we can remove a lot of code noise by unconditionally evaluating the condition even in assertion-disabled builds.
1535 lines
66 KiB
C++
1535 lines
66 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.
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
#ifndef INCLUDED_BY_EMITTER
|
|
#include <CodeEmitter/Emitter.h>
|
|
namespace ARMEmitter {
|
|
struct EmitterOps : Emitter {
|
|
#endif
|
|
|
|
public:
|
|
// Advanced SIMD scalar copy
|
|
void dup(ScalarRegSize size, VRegister rd, VRegister rn, uint32_t Index) {
|
|
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_A_FMT(Index < MaxIndex, "Index too large. Index={}, Max Index: {}", Index, MaxIndex);
|
|
|
|
const uint32_t imm5 = (Index << IndexShift) | ElementSize;
|
|
|
|
ASIMDScalarCopy(1, 1, imm5, 0b0000, rd, rn);
|
|
}
|
|
|
|
void mov(ScalarRegSize size, VRegister rd, 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
|
|
void sqrdmlah(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
|
|
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i16Bit || size == ScalarRegSize::i32Bit, "Only supports 16/32-bit");
|
|
ASIMDScalarThreeSameExtra(1, size, 0b0000, rm, rn, rd);
|
|
}
|
|
void sqrdmlsh(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm) {
|
|
LOGMAN_THROW_A_FMT(size == ScalarRegSize::i16Bit || size == ScalarRegSize::i32Bit, "Only supports 16/32-bit");
|
|
ASIMDScalarThreeSameExtra(1, size, 0b0001, rm, rn, rd);
|
|
}
|
|
|
|
// 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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_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(1, 1, ConvertedSize, 0b01100, rd, rn);
|
|
}
|
|
void faddp(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(1, 1, ConvertedSize, 0b01101, rd, rn);
|
|
}
|
|
void fmaxp(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(1, 1, ConvertedSize, 0b01111, rd, rn);
|
|
}
|
|
void fminnmp(ScalarRegSize size, VRegister rd, VRegister rn) {
|
|
LOGMAN_THROW_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_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_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_FMT(Shift > 0 && Shift < 64, "Invalid shift for sshr");
|
|
LOGMAN_THROW_A_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_A_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_A_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_A_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_A_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
|
|
void sqdmlal(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i64Bit, "Scalar size must not be 64-bit");
|
|
ASIMDScalarXIndexedElement(0, size, 0b0011, rm, rn, rd, index);
|
|
}
|
|
void sqdmlsl(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i64Bit, "Scalar size must not be 64-bit");
|
|
ASIMDScalarXIndexedElement(0, size, 0b0111, rm, rn, rd, index);
|
|
}
|
|
void sqdmull(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i64Bit, "Scalar size must not be 64-bit");
|
|
ASIMDScalarXIndexedElement(0, size, 0b1011, rm, rn, rd, index);
|
|
}
|
|
void sqdmulh(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i64Bit, "Scalar size must not be 64-bit");
|
|
ASIMDScalarXIndexedElement(0, size, 0b1100, rm, rn, rd, index);
|
|
}
|
|
void sqrdmulh(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i64Bit, "Scalar size must not be 64-bit");
|
|
ASIMDScalarXIndexedElement(0, size, 0b1101, rm, rn, rd, index);
|
|
}
|
|
void fmla(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
ASIMDScalarXIndexedElement(0, size, 0b0001, rm, rn, rd, index);
|
|
}
|
|
void fmls(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
ASIMDScalarXIndexedElement(0, size, 0b0101, rm, rn, rd, index);
|
|
}
|
|
void fmul(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
ASIMDScalarXIndexedElement(0, size, 0b1001, rm, rn, rd, index);
|
|
}
|
|
void sqrdmlah(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i64Bit, "Scalar size must not be 64-bit");
|
|
ASIMDScalarXIndexedElement(1, size, 0b1101, rm, rn, rd, index);
|
|
}
|
|
void sqrdmlsh(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i64Bit, "Scalar size must not be 64-bit");
|
|
ASIMDScalarXIndexedElement(1, size, 0b1111, rm, rn, rd, index);
|
|
}
|
|
void fmulx(ScalarRegSize size, VRegister rd, VRegister rn, VRegister rm, uint32_t index) {
|
|
ASIMDScalarXIndexedElement(1, size, 0b1001, rm, rn, rd, index);
|
|
}
|
|
|
|
// 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_A_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_A_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 Q, uint32_t b28, uint32_t imm5, uint32_t imm4, VRegister rd, VRegister rn) {
|
|
uint32_t Instr = 0b0000'1110'0000'0000'0000'01U << 10;
|
|
Instr |= Q << 30;
|
|
Instr |= b28 << 28;
|
|
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
|
|
void ASIMDScalarThreeSameExtra(uint32_t U, ScalarRegSize size, uint32_t opcode, VRegister rm, VRegister rn, VRegister rd) {
|
|
uint32_t Instr = 0b0101'1110'0000'0000'1000'0100'0000'0000;
|
|
Instr |= U << 29;
|
|
Instr |= FEXCore::ToUnderlying(size) << 22;
|
|
Instr |= rm.Idx() << 16;
|
|
Instr |= opcode << 11;
|
|
Instr |= rn.Idx() << 5;
|
|
Instr |= rd.Idx();
|
|
dc32(Instr);
|
|
}
|
|
|
|
// 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 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
|
|
void ASIMDScalarXIndexedElement(uint32_t U, ScalarRegSize size, uint32_t opcode, VRegister rm, VRegister rn, VRegister rd, uint32_t index) {
|
|
LOGMAN_THROW_A_FMT(size != ScalarRegSize::i8Bit, "Scalar size must not be 8-bit");
|
|
|
|
const auto invalid_bound = 16U >> FEXCore::ToUnderlying(size);
|
|
LOGMAN_THROW_A_FMT(index < invalid_bound, "Index ({}) must be within [0-{}]", index, invalid_bound - 1);
|
|
|
|
uint32_t Instr = 0b0101'1111'0000'0000'0000'0000'0000'0000;
|
|
|
|
// FMUL/FMLA/FMLS indexed variants deal with size differently.
|
|
if (opcode == 0b0001 || opcode == 0b0101 || opcode == 0b1001) {
|
|
// Unlike other instructions in the group, 16-bit is encoded as zero
|
|
// and 32/64-bit are encoded with the top bit always set to one.
|
|
if (size != ScalarRegSize::i16Bit) {
|
|
Instr |= (0b10 | (FEXCore::ToUnderlying(size) & 1)) << 22;
|
|
}
|
|
} else {
|
|
Instr |= FEXCore::ToUnderlying(size) << 22;
|
|
}
|
|
|
|
uint32_t H = 0;
|
|
uint32_t LM = 0;
|
|
if (size == ScalarRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(rm <= VReg::v15, "rm ({}) must be within [v0-v15]", rm.Idx());
|
|
H = (index >> 2) & 1;
|
|
LM = index & 0b11;
|
|
} else if (size == ScalarRegSize::i32Bit) {
|
|
H = (index >> 1) & 1;
|
|
LM = (index & 0b01) << 1;
|
|
} else {
|
|
H = index & 1;
|
|
}
|
|
|
|
Instr |= U << 29;
|
|
Instr |= LM << 20;
|
|
Instr |= rm.Idx() << 16;
|
|
Instr |= opcode << 12;
|
|
Instr |= H << 11;
|
|
Instr |= rn.Idx() << 5;
|
|
Instr |= rd.Idx();
|
|
dc32(Instr);
|
|
}
|
|
|
|
// 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_A_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_A_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);
|
|
}
|
|
|
|
#ifndef INCLUDED_BY_EMITTER
|
|
}; // struct LoadstoreEmitterOps
|
|
} // namespace ARMEmitter
|
|
#endif
|