Move dead submodules in-tree

Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
swurl 2025-05-31 02:33:02 -04:00
parent c0cceff365
commit 6c655321e6
No known key found for this signature in database
GPG key ID: A5A7629F109C8FD1
4081 changed files with 1185566 additions and 45 deletions

View file

@ -0,0 +1,211 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
template<std::uint32_t mask_>
static constexpr std::uint32_t pdep(std::uint32_t val)
{
std::uint32_t mask = mask_;
std::uint32_t res = 0;
for (std::uint32_t bb = 1; mask; bb += bb) {
if (val & bb)
res |= mask & (~mask + 1);
mask &= mask - 1;
}
return res;
}
#define OAKNUT_STD_ENCODE(TYPE, ACCESS, SIZE) \
template<std::uint32_t splat> \
std::uint32_t encode(TYPE v) \
{ \
static_assert(std::popcount(splat) == SIZE); \
return pdep<splat>(static_cast<std::uint32_t>(ACCESS)); \
}
OAKNUT_STD_ENCODE(RReg, v.index() & 31, 5)
OAKNUT_STD_ENCODE(VReg, v.index() & 31, 5)
OAKNUT_STD_ENCODE(VRegArranged, v.index() & 31, 5)
OAKNUT_STD_ENCODE(AddSubImm, v.m_encoded, 13)
OAKNUT_STD_ENCODE(BitImm32, v.m_encoded, 12)
OAKNUT_STD_ENCODE(BitImm64, v.m_encoded, 13)
OAKNUT_STD_ENCODE(LslShift<32>, v.m_encoded, 12)
OAKNUT_STD_ENCODE(LslShift<64>, v.m_encoded, 12)
OAKNUT_STD_ENCODE(FImm8, v.m_encoded, 8)
OAKNUT_STD_ENCODE(RepImm, v.m_encoded, 8)
OAKNUT_STD_ENCODE(Cond, v, 4)
OAKNUT_STD_ENCODE(Rot, v, 2)
OAKNUT_STD_ENCODE(AddSubExt, v, 3)
OAKNUT_STD_ENCODE(IndexExt, v, 3)
OAKNUT_STD_ENCODE(AddSubShift, v, 2)
OAKNUT_STD_ENCODE(LogShift, v, 2)
OAKNUT_STD_ENCODE(PstateField, v, 6)
OAKNUT_STD_ENCODE(SystemReg, v, 15)
OAKNUT_STD_ENCODE(AtOp, v, 7)
OAKNUT_STD_ENCODE(BarrierOp, v, 4)
OAKNUT_STD_ENCODE(DcOp, v, 10)
OAKNUT_STD_ENCODE(IcOp, v, 10)
OAKNUT_STD_ENCODE(PrfOp, v, 5)
OAKNUT_STD_ENCODE(TlbiOp, v, 10)
template<std::uint32_t splat>
std::uint32_t encode(MovImm16 v)
{
static_assert(std::popcount(splat) == 17 || std::popcount(splat) == 18);
if constexpr (std::popcount(splat) == 17) {
constexpr std::uint32_t mask = (1 << std::popcount(splat)) - 1;
if ((v.m_encoded & mask) != v.m_encoded)
throw OaknutException{ExceptionType::InvalidMovImm16};
}
return pdep<splat>(v.m_encoded);
}
template<std::uint32_t splat, std::size_t imm_size>
std::uint32_t encode(Imm<imm_size> v)
{
static_assert(std::popcount(splat) >= imm_size);
return pdep<splat>(v.value());
}
template<std::uint32_t splat, int A, int B>
std::uint32_t encode(ImmChoice<A, B> v)
{
static_assert(std::popcount(splat) == 1);
return pdep<splat>(v.m_encoded);
}
template<std::uint32_t splat, int A, int B, int C, int D>
std::uint32_t encode(ImmChoice<A, B, C, D> v)
{
static_assert(std::popcount(splat) == 2);
return pdep<splat>(v.m_encoded);
}
template<std::uint32_t splat, std::size_t size, std::size_t align>
std::uint32_t encode(SOffset<size, align> v)
{
static_assert(std::popcount(splat) == size - align);
return pdep<splat>(v.m_encoded);
}
template<std::uint32_t splat, std::size_t size, std::size_t align>
std::uint32_t encode(POffset<size, align> v)
{
static_assert(std::popcount(splat) == size - align);
return pdep<splat>(v.m_encoded);
}
template<std::uint32_t splat>
std::uint32_t encode(std::uint32_t v)
{
return pdep<splat>(v);
}
template<std::uint32_t splat, typename T, size_t N>
std::uint32_t encode(List<T, N> v)
{
return encode<splat>(v.m_base);
}
template<std::uint32_t splat, std::size_t size, std::size_t align>
std::uint32_t encode(AddrOffset<size, align> v)
{
static_assert(std::popcount(splat) == size - align);
const auto encode_fn = [](std::ptrdiff_t current_offset, std::ptrdiff_t target_offset) {
const std::ptrdiff_t diff = target_offset - current_offset;
return pdep<splat>(AddrOffset<size, align>::encode(diff));
};
return std::visit(detail::overloaded{
[&](std::uint32_t encoding) -> std::uint32_t {
return pdep<splat>(encoding);
},
[&](Label* label) -> std::uint32_t {
if (label->m_offset) {
return encode_fn(Policy::offset(), *label->m_offset);
}
label->m_wbs.emplace_back(Label::Writeback{Policy::offset(), ~splat, static_cast<Label::EmitFunctionType>(encode_fn)});
return 0u;
},
[&](const void* p) -> std::uint32_t {
const std::ptrdiff_t diff = reinterpret_cast<std::uintptr_t>(p) - Policy::template xptr<std::uintptr_t>();
return pdep<splat>(AddrOffset<size, align>::encode(diff));
},
},
v.m_payload);
}
template<std::uint32_t splat, std::size_t size, std::size_t shift_amount>
std::uint32_t encode(PageOffset<size, shift_amount> v)
{
static_assert(std::popcount(splat) == size);
const auto encode_fn = [](std::ptrdiff_t current_offset, std::ptrdiff_t target_offset) {
return pdep<splat>(PageOffset<size, shift_amount>::encode(static_cast<std::uintptr_t>(current_offset), static_cast<std::uintptr_t>(target_offset)));
};
return std::visit(detail::overloaded{
[&](Label* label) -> std::uint32_t {
if (label->m_offset) {
return encode_fn(Policy::offset(), *label->m_offset);
}
label->m_wbs.emplace_back(Label::Writeback{Policy::offset(), ~splat, static_cast<Label::EmitFunctionType>(encode_fn)});
return 0u;
},
[&](const void* p) -> std::uint32_t {
return pdep<splat>(PageOffset<size, shift_amount>::encode(Policy::template xptr<std::uintptr_t>(), reinterpret_cast<std::ptrdiff_t>(p)));
},
},
v.m_payload);
}
#undef OAKNUT_STD_ENCODE
void addsubext_lsl_correction(AddSubExt& ext, XRegSp)
{
if (ext == AddSubExt::LSL)
ext = AddSubExt::UXTX;
}
void addsubext_lsl_correction(AddSubExt& ext, WRegWsp)
{
if (ext == AddSubExt::LSL)
ext = AddSubExt::UXTW;
}
void addsubext_lsl_correction(AddSubExt& ext, XReg)
{
if (ext == AddSubExt::LSL)
ext = AddSubExt::UXTX;
}
void addsubext_lsl_correction(AddSubExt& ext, WReg)
{
if (ext == AddSubExt::LSL)
ext = AddSubExt::UXTW;
}
void addsubext_verify_reg_size(AddSubExt ext, RReg rm)
{
if (rm.bitsize() == 32 && (static_cast<int>(ext) & 0b011) != 0b011)
return;
if (rm.bitsize() == 64 && (static_cast<int>(ext) & 0b011) == 0b011)
return;
throw OaknutException{ExceptionType::InvalidAddSubExt};
}
void indexext_verify_reg_size(IndexExt ext, RReg rm)
{
if (rm.bitsize() == 32 && (static_cast<int>(ext) & 1) == 0)
return;
if (rm.bitsize() == 64 && (static_cast<int>(ext) & 1) == 1)
return;
throw OaknutException{ExceptionType::InvalidIndexExt};
}
void tbz_verify_reg_size(RReg rt, Imm<6> imm)
{
if (rt.bitsize() == 32 && imm.value() >= 32)
throw OaknutException{ExceptionType::BitPositionOutOfRange};
}

View file

@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: Copyright (c) 2023 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
OAKNUT_CPU_FEATURE(FP)
OAKNUT_CPU_FEATURE(ASIMD)
OAKNUT_CPU_FEATURE(AES)
OAKNUT_CPU_FEATURE(PMULL)
OAKNUT_CPU_FEATURE(SHA1)
OAKNUT_CPU_FEATURE(SHA256)
OAKNUT_CPU_FEATURE(CRC32)
OAKNUT_CPU_FEATURE(LSE)
OAKNUT_CPU_FEATURE(FP16Conv)
OAKNUT_CPU_FEATURE(FP16)
OAKNUT_CPU_FEATURE(RDM)
OAKNUT_CPU_FEATURE(JSCVT)
OAKNUT_CPU_FEATURE(FCMA)
OAKNUT_CPU_FEATURE(LRCPC)
OAKNUT_CPU_FEATURE(DPB)
OAKNUT_CPU_FEATURE(SHA3)
OAKNUT_CPU_FEATURE(SM3)
OAKNUT_CPU_FEATURE(SM4)
OAKNUT_CPU_FEATURE(DotProd)
OAKNUT_CPU_FEATURE(SHA512)
OAKNUT_CPU_FEATURE(SVE)
OAKNUT_CPU_FEATURE(FHM)
OAKNUT_CPU_FEATURE(DIT)
OAKNUT_CPU_FEATURE(LSE2)
OAKNUT_CPU_FEATURE(LRCPC2)
OAKNUT_CPU_FEATURE(FlagM)
OAKNUT_CPU_FEATURE(SSBS)
OAKNUT_CPU_FEATURE(SB)
OAKNUT_CPU_FEATURE(PACA)
OAKNUT_CPU_FEATURE(PACG)
OAKNUT_CPU_FEATURE(DPB2)
OAKNUT_CPU_FEATURE(SVE2)
OAKNUT_CPU_FEATURE(SVE_AES)
OAKNUT_CPU_FEATURE(SVE_PMULL128)
OAKNUT_CPU_FEATURE(SVE_BITPERM)
OAKNUT_CPU_FEATURE(SVE_SHA3)
OAKNUT_CPU_FEATURE(SVE_SM4)
OAKNUT_CPU_FEATURE(FlagM2)
OAKNUT_CPU_FEATURE(FRINTTS)
OAKNUT_CPU_FEATURE(SVE_I8MM)
OAKNUT_CPU_FEATURE(SVE_F32MM)
OAKNUT_CPU_FEATURE(SVE_F64MM)
OAKNUT_CPU_FEATURE(SVE_BF16)
OAKNUT_CPU_FEATURE(I8MM)
OAKNUT_CPU_FEATURE(BF16)
OAKNUT_CPU_FEATURE(DGH)
OAKNUT_CPU_FEATURE(RNG)
OAKNUT_CPU_FEATURE(BTI)
OAKNUT_CPU_FEATURE(MTE)
OAKNUT_CPU_FEATURE(ECV)
OAKNUT_CPU_FEATURE(AFP)
OAKNUT_CPU_FEATURE(RPRES)
OAKNUT_CPU_FEATURE(MTE3)
OAKNUT_CPU_FEATURE(SME)
OAKNUT_CPU_FEATURE(SME_I16I64)
OAKNUT_CPU_FEATURE(SME_F64F64)
OAKNUT_CPU_FEATURE(SME_I8I32)
OAKNUT_CPU_FEATURE(SME_F16F32)
OAKNUT_CPU_FEATURE(SME_B16F32)
OAKNUT_CPU_FEATURE(SME_F32F32)
OAKNUT_CPU_FEATURE(SME_FA64)
OAKNUT_CPU_FEATURE(WFxT)
OAKNUT_CPU_FEATURE(EBF16)
OAKNUT_CPU_FEATURE(SVE_EBF16)
OAKNUT_CPU_FEATURE(CSSC)
OAKNUT_CPU_FEATURE(RPRFM)
OAKNUT_CPU_FEATURE(SVE2p1)
OAKNUT_CPU_FEATURE(SME2)
OAKNUT_CPU_FEATURE(SME2p1)
OAKNUT_CPU_FEATURE(SME_I16I32)
OAKNUT_CPU_FEATURE(SME_BI32I32)
OAKNUT_CPU_FEATURE(SME_B16B16)
OAKNUT_CPU_FEATURE(SME_F16F16)
OAKNUT_CPU_FEATURE(MOPS)
OAKNUT_CPU_FEATURE(HBC)

View file

@ -0,0 +1,310 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
namespace oaknut {
struct PostIndexed {};
struct PreIndexed {};
enum class LslSymbol {
LSL,
};
enum class MslSymbol {
MSL,
};
enum class Cond {
EQ,
NE,
CS,
CC,
MI,
PL,
VS,
VC,
HI,
LS,
GE,
LT,
GT,
LE,
AL,
NV,
HS = CS,
LO = CC,
};
constexpr Cond invert(Cond c)
{
return static_cast<Cond>(static_cast<unsigned>(c) ^ 1);
}
enum class Rot {
DEG_0 = 0b00,
DEG_90 = 0b01,
DEG_180 = 0b10,
DEG_270 = 0b11,
};
enum class AddSubExt {
UXTB,
UXTH,
UXTW,
UXTX,
SXTB,
SXTH,
SXTW,
SXTX,
LSL, // UXTW (32-bit) or UXTX (64-bit)
};
enum class IndexExt {
UXTW = 0b010,
LSL = 0b011,
SXTW = 0b110,
SXTX = 0b111,
};
enum class AddSubShift {
LSL,
LSR,
ASR,
};
enum class LogShift {
LSL,
LSR,
ASR,
ROR,
};
enum class PstateField {
UAO = 0b000'011, // ARMv8.2-UAO
PAN = 0b000'100, // ARMv8.1-PAN
SPSel = 0b000'101,
DIT = 0b011'010, // ARMv8.4-DIT
DAIFSet = 0b011'110,
DAIFClr = 0b011'111,
};
enum class SystemReg {
AMCFGR_EL0 = 0b11'011'1101'0010'001,
AMCGCR_EL0 = 0b11'011'1101'0010'010,
AMCNTENCLR0_EL0 = 0b11'011'1101'0010'100,
AMCNTENCLR1_EL0 = 0b11'011'1101'0011'000,
AMCNTENSET0_EL0 = 0b11'011'1101'0010'101,
AMCNTENSET1_EL0 = 0b11'011'1101'0011'001,
AMCR_EL0 = 0b11'011'1101'0010'000,
AMEVCNTR0_n_EL0 = 0b11'011'1101'0100'000, // n = 0-3
AMEVCNTR1_n_EL0 = 0b11'011'1101'1100'000, // n = 0-15
AMEVTYPER0_n_EL0 = 0b11'011'1101'0110'000, // n = 0-3
AMEVTYPER1_n_EL0 = 0b11'011'1101'1110'000, // n = 0-15
AMUSERENR_EL0 = 0b11'011'1101'0010'011,
CNTFRQ_EL0 = 0b11'011'1110'0000'000,
CNTP_CTL_EL0 = 0b11'011'1110'0010'001,
CNTP_CVAL_EL0 = 0b11'011'1110'0010'010,
CNTP_TVAL_EL0 = 0b11'011'1110'0010'000,
CNTPCT_EL0 = 0b11'011'1110'0000'001,
CNTV_CTL_EL0 = 0b11'011'1110'0011'001,
CNTV_CVAL_EL0 = 0b11'011'1110'0011'010,
CNTV_TVAL_EL0 = 0b11'011'1110'0011'000,
CNTVCT_EL0 = 0b11'011'1110'0000'010,
CTR_EL0 = 0b11'011'0000'0000'001,
CurrentEL = 0b11'000'0100'0010'010,
DAIF = 0b11'011'0100'0010'001,
DBGDTR_EL0 = 0b10'011'0000'0100'000,
DBGDTRRX_EL0 = 0b10'011'0000'0101'000,
DBGDTRTX_EL0 = 0b10'011'0000'0101'000,
DCZID_EL0 = 0b11'011'0000'0000'111,
DIT = 0b11'011'0100'0010'101,
DLR_EL0 = 0b11'011'0100'0101'001,
DSPSR_EL0 = 0b11'011'0100'0101'000,
FPCR = 0b11'011'0100'0100'000,
FPSR = 0b11'011'0100'0100'001,
MDCCSR_EL0 = 0b10'011'0000'0001'000,
NZCV = 0b11'011'0100'0010'000,
PAN = 0b11'000'0100'0010'011,
PMCCFILTR_EL0 = 0b11'011'1110'1111'111,
PMCCNTR_EL0 = 0b11'011'1001'1101'000,
PMCEID0_EL0 = 0b11'011'1001'1100'110,
PMCEID1_EL0 = 0b11'011'1001'1100'111,
PMCNTENCLR_EL0 = 0b11'011'1001'1100'010,
PMCNTENSET_EL0 = 0b11'011'1001'1100'001,
PMCR_EL0 = 0b11'011'1001'1100'000,
PMEVCNTR_n_EL0 = 0b11'011'1110'1000'000, // n = 0-30
PMEVTYPER_n_EL0 = 0b11'011'1110'1100'000, // n = 0-30
PMOVSCLR_EL0 = 0b11'011'1001'1100'011,
PMOVSSET_EL0 = 0b11'011'1001'1110'011,
PMSELR_EL0 = 0b11'011'1001'1100'101,
PMSWINC_EL0 = 0b11'011'1001'1100'100,
PMUSERENR_EL0 = 0b11'011'1001'1110'000,
PMXEVCNTR_EL0 = 0b11'011'1001'1101'010,
PMXEVTYPER_EL0 = 0b11'011'1001'1101'001,
SP_EL0 = 0b11'000'0100'0001'000,
SPSel = 0b11'000'0100'0010'000,
SPSR_abt = 0b11'100'0100'0011'001,
SPSR_fiq = 0b11'100'0100'0011'011,
SPSR_irq = 0b11'100'0100'0011'000,
SPSR_und = 0b11'100'0100'0011'010,
TPIDR_EL0 = 0b11'011'1101'0000'010,
TPIDRRO_EL0 = 0b11'011'1101'0000'011,
UAO = 0b11'000'0100'0010'100,
};
enum class AtOp {
S1E1R = 0b000'0'000,
S1E1W = 0b000'0'001,
S1E0R = 0b000'0'010,
S1E0W = 0b000'0'011,
S1E1RP = 0b000'1'000, // ARMv8.2-ATS1E1
S1E1WP = 0b000'1'001, // ARMv8.2-ATS1E1
S1E2R = 0b100'0'000,
S1E2W = 0b100'0'001,
S12E1R = 0b100'0'100,
S12E1W = 0b100'0'101,
S12E0R = 0b100'0'110,
S12E0W = 0b100'0'111,
S1E3R = 0b110'0'000,
S1E3W = 0b110'0'001,
};
enum class BarrierOp {
SY = 0b1111,
ST = 0b1110,
LD = 0b1101,
ISH = 0b1011,
ISHST = 0b1010,
ISHLD = 0b1001,
NSH = 0b0111,
NSHST = 0b0110,
NSHLD = 0b0101,
OSH = 0b0011,
OSHST = 0b0010,
OSHLD = 0b0001,
};
enum class DcOp {
IVAC = 0b000'0110'001,
ISW = 0b000'0110'010,
CSW = 0b000'1010'010,
CISW = 0b000'1110'010,
ZVA = 0b011'0100'001,
CVAC = 0b011'1010'001,
CVAU = 0b011'1011'001,
CVAP = 0b011'1100'001, // ARMv8.2-DCPoP
CIVAC = 0b011'1110'001,
};
enum class IcOp {
IALLUIS = 0b000'0001'000,
IALLU = 0b000'0101'000,
IVAU = 0b011'0101'001,
};
enum class PrfOp {
PLDL1KEEP = 0b00'00'0,
PLDL1STRM = 0b00'00'1,
PLDL2KEEP = 0b00'01'0,
PLDL2STRM = 0b00'01'1,
PLDL3KEEP = 0b00'10'0,
PLDL3STRM = 0b00'10'1,
PLIL1KEEP = 0b01'00'0,
PLIL1STRM = 0b01'00'1,
PLIL2KEEP = 0b01'01'0,
PLIL2STRM = 0b01'01'1,
PLIL3KEEP = 0b01'10'0,
PLIL3STRM = 0b01'10'1,
PSTL1KEEP = 0b10'00'0,
PSTL1STRM = 0b10'00'1,
PSTL2KEEP = 0b10'01'0,
PSTL2STRM = 0b10'01'1,
PSTL3KEEP = 0b10'10'0,
PSTL3STRM = 0b10'10'1,
};
enum class TlbiOp {
VMALLE1OS = 0b000'0001'000, // ARMv8.4-TLBI
VAE1OS = 0b000'0001'001, // ARMv8.4-TLBI
ASIDE1OS = 0b000'0001'010, // ARMv8.4-TLBI
VAAE1OS = 0b000'0001'011, // ARMv8.4-TLBI
VALE1OS = 0b000'0001'101, // ARMv8.4-TLBI
VAALE1OS = 0b000'0001'111, // ARMv8.4-TLBI
RVAE1IS = 0b000'0010'001, // ARMv8.4-TLBI
RVAAE1IS = 0b000'0010'011, // ARMv8.4-TLBI
RVALE1IS = 0b000'0010'101, // ARMv8.4-TLBI
RVAALE1IS = 0b000'0010'111, // ARMv8.4-TLBI
VMALLE1IS = 0b000'0011'000,
VAE1IS = 0b000'0011'001,
ASIDE1IS = 0b000'0011'010,
VAAE1IS = 0b000'0011'011,
VALE1IS = 0b000'0011'101,
VAALE1IS = 0b000'0011'111,
RVAE1OS = 0b000'0101'001, // ARMv8.4-TLBI
RVAAE1OS = 0b000'0101'011, // ARMv8.4-TLBI
RVALE1OS = 0b000'0101'101, // ARMv8.4-TLBI
RVAALE1OS = 0b000'0101'111, // ARMv8.4-TLBI
RVAE1 = 0b000'0110'001, // ARMv8.4-TLBI
RVAAE1 = 0b000'0110'011, // ARMv8.4-TLBI
RVALE1 = 0b000'0110'101, // ARMv8.4-TLBI
RVAALE1 = 0b000'0110'111, // ARMv8.4-TLBI
VMALLE1 = 0b000'0111'000,
VAE1 = 0b000'0111'001,
ASIDE1 = 0b000'0111'010,
VAAE1 = 0b000'0111'011,
VALE1 = 0b000'0111'101,
VAALE1 = 0b000'0111'111,
IPAS2E1IS = 0b100'0000'001,
RIPAS2E1IS = 0b100'0000'010, // ARMv8.4-TLBI
IPAS2LE1IS = 0b100'0000'101,
RIPAS2LE1IS = 0b100'0000'110, // ARMv8.4-TLBI
ALLE2OS = 0b100'0001'000, // ARMv8.4-TLBI
VAE2OS = 0b100'0001'001, // ARMv8.4-TLBI
ALLE1OS = 0b100'0001'100, // ARMv8.4-TLBI
VALE2OS = 0b100'0001'101, // ARMv8.4-TLBI
VMALLS12E1OS = 0b100'0001'110, // ARMv8.4-TLBI
RVAE2IS = 0b100'0010'001, // ARMv8.4-TLBI
RVALE2IS = 0b100'0010'101, // ARMv8.4-TLBI
ALLE2IS = 0b100'0011'000,
VAE2IS = 0b100'0011'001,
ALLE1IS = 0b100'0011'100,
VALE2IS = 0b100'0011'101,
VMALLS12E1IS = 0b100'0011'110,
IPAS2E1OS = 0b100'0100'000, // ARMv8.4-TLBI
IPAS2E1 = 0b100'0100'001,
RIPAS2E1 = 0b100'0100'010, // ARMv8.4-TLBI
RIPAS2E1OS = 0b100'0100'011, // ARMv8.4-TLBI
IPAS2LE1OS = 0b100'0100'100, // ARMv8.4-TLBI
IPAS2LE1 = 0b100'0100'101,
RIPAS2LE1 = 0b100'0100'110, // ARMv8.4-TLBI
RIPAS2LE1OS = 0b100'0100'111, // ARMv8.4-TLBI
RVAE2OS = 0b100'0101'001, // ARMv8.4-TLBI
RVALE2OS = 0b100'0101'101, // ARMv8.4-TLBI
RVAE2 = 0b100'0110'001, // ARMv8.4-TLBI
RVALE2 = 0b100'0110'101, // ARMv8.4-TLBI
ALLE2 = 0b100'0111'000,
VAE2 = 0b100'0111'001,
ALLE1 = 0b100'0111'100,
VALE2 = 0b100'0111'101,
VMALLS12E1 = 0b100'0111'110,
ALLE3OS = 0b110'0001'000, // ARMv8.4-TLBI
VAE3OS = 0b110'0001'001, // ARMv8.4-TLBI
VALE3OS = 0b110'0001'101, // ARMv8.4-TLBI
RVAE3IS = 0b110'0010'001, // ARMv8.4-TLBI
RVALE3IS = 0b110'0010'101, // ARMv8.4-TLBI
ALLE3IS = 0b110'0011'000,
VAE3IS = 0b110'0011'001,
VALE3IS = 0b110'0011'101,
RVAE3OS = 0b110'0101'001, // ARMv8.4-TLBI
RVALE3OS = 0b110'0101'101, // ARMv8.4-TLBI
RVAE3 = 0b110'0110'001, // ARMv8.4-TLBI
RVALE3 = 0b110'0110'101, // ARMv8.4-TLBI
ALLE3 = 0b110'0111'000,
VAE3 = 0b110'0111'001,
VALE3 = 0b110'0111'101,
};
} // namespace oaknut

View file

@ -0,0 +1,319 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
#include <bit>
#include <compare>
#include <cstddef>
#include <cstdint>
#include <optional>
#include "oaknut/oaknut_exception.hpp"
namespace oaknut {
template<std::size_t bit_size_>
struct Imm {
public:
static_assert(bit_size_ != 0 && bit_size_ <= 32, "Invalid bit_size");
static constexpr std::size_t bit_size = bit_size_;
static constexpr std::uint32_t mask = (1 << bit_size) - 1;
constexpr /* implicit */ Imm(std::uint32_t value_)
: m_value(value_)
{
if (!is_valid(value_))
throw OaknutException{ExceptionType::ImmOutOfRange};
}
constexpr auto operator<=>(const Imm& other) const { return m_value <=> other.m_value; }
constexpr auto operator<=>(std::uint32_t other) const { return operator<=>(Imm{other}); }
constexpr std::uint32_t value() const { return m_value; }
static bool is_valid(std::uint32_t value_)
{
return ((value_ & mask) == value_);
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_value;
};
enum class AddSubImmShift {
SHL_0,
SHL_12,
};
struct AddSubImm {
public:
constexpr AddSubImm(std::uint32_t value_, AddSubImmShift shift_)
: m_encoded(value_ | ((shift_ == AddSubImmShift::SHL_12) ? 1 << 12 : 0))
{
if ((value_ & 0xFFF) != value_)
throw OaknutException{ExceptionType::InvalidAddSubImm};
}
constexpr /* implicit */ AddSubImm(std::uint64_t value_)
{
if ((value_ & 0xFFF) == value_) {
m_encoded = static_cast<std::uint32_t>(value_);
} else if ((value_ & 0xFFF000) == value_) {
m_encoded = static_cast<std::uint32_t>((value_ >> 12) | (1 << 12));
} else {
throw OaknutException{ExceptionType::InvalidAddSubImm};
}
}
static constexpr bool is_valid(std::uint64_t value_)
{
return ((value_ & 0xFFF) == value_) || ((value_ & 0xFFF000) == value_);
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
enum class MovImm16Shift {
SHL_0,
SHL_16,
SHL_32,
SHL_48,
};
struct MovImm16 {
public:
MovImm16(std::uint16_t value_, MovImm16Shift shift_)
: m_encoded(static_cast<std::uint32_t>(value_) | (static_cast<std::uint32_t>(shift_) << 16))
{}
constexpr /* implict */ MovImm16(std::uint64_t value_)
{
std::uint32_t shift = 0;
while (value_ != 0) {
const std::uint32_t lsw = static_cast<std::uint16_t>(value_ & 0xFFFF);
if (value_ == lsw) {
m_encoded = lsw | (shift << 16);
return;
} else if (lsw != 0) {
throw OaknutException{ExceptionType::InvalidMovImm16};
}
value_ >>= 16;
shift++;
}
}
static constexpr bool is_valid(std::uint64_t value_)
{
return ((value_ & 0xFFFF) == value_) || ((value_ & 0xFFFF0000) == value_) || ((value_ & 0xFFFF00000000) == value_) || ((value_ & 0xFFFF000000000000) == value_);
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded = 0;
};
namespace detail {
constexpr std::optional<std::uint32_t> encode_bit_imm(std::uint64_t value)
{
if (value == 0 || (~value) == 0)
return std::nullopt;
const int rotation = std::countr_zero(value & (value + 1));
const std::uint64_t rot_value = std::rotr(value, rotation);
const int esize = std::countr_zero(rot_value & (rot_value + 1));
const int ones = std::countr_one(rot_value);
if (std::rotr(value, esize) != value)
return std::nullopt;
const int S = ((-esize) << 1) | (ones - 1);
const int R = (esize - rotation) & (esize - 1);
const int N = (~S >> 6) & 1;
return static_cast<std::uint32_t>((S & 0b111111) | (R << 6) | (N << 12));
}
constexpr std::optional<std::uint32_t> encode_bit_imm(std::uint32_t value)
{
const std::uint64_t value_u64 = (static_cast<std::uint64_t>(value) << 32) | static_cast<std::uint64_t>(value);
const auto result = encode_bit_imm(value_u64);
if (result && (*result & 0b0'111111'111111) != *result)
return std::nullopt;
return result;
}
} // namespace detail
struct BitImm32 {
public:
constexpr BitImm32(Imm<6> imms, Imm<6> immr)
: m_encoded((imms.value() << 6) | immr.value())
{}
constexpr /* implicit */ BitImm32(std::uint32_t value)
{
const auto encoded = detail::encode_bit_imm(value);
if (!encoded || (*encoded & 0x1000) != 0)
throw OaknutException{ExceptionType::InvalidBitImm32};
m_encoded = *encoded;
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
struct BitImm64 {
public:
constexpr BitImm64(bool N, Imm<6> imms, Imm<6> immr)
: m_encoded((N ? 1 << 12 : 0) | (imms.value() << 6) | immr.value())
{}
constexpr /* implicit */ BitImm64(std::uint64_t value)
{
const auto encoded = detail::encode_bit_imm(value);
if (!encoded)
throw OaknutException{ExceptionType::InvalidBitImm64};
m_encoded = *encoded;
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
struct FImm8 {
public:
constexpr explicit FImm8(std::uint8_t encoded)
: m_encoded(encoded)
{}
constexpr FImm8(bool sign, Imm<3> exp, Imm<4> mantissa)
: m_encoded((sign ? 1 << 7 : 0) | (exp.value() << 4) | (mantissa.value()))
{}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
struct RepImm {
public:
constexpr explicit RepImm(std::uint8_t encoded)
: m_encoded(encoded)
{}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
template<int A>
struct ImmConst {
constexpr /* implicit */ ImmConst(int value)
{
if (value != A) {
throw OaknutException{ExceptionType::InvalidImmConst};
}
}
};
struct ImmConstFZero {
constexpr /* implicit */ ImmConstFZero(double value)
{
if (value != 0) {
throw OaknutException{ExceptionType::InvalidImmConstFZero};
}
}
};
template<int...>
struct ImmChoice;
template<int A, int B>
struct ImmChoice<A, B> {
constexpr /* implicit */ ImmChoice(int value)
{
if (value == A) {
m_encoded = 0;
} else if (value == B) {
m_encoded = 1;
} else {
throw OaknutException{ExceptionType::InvalidImmChoice};
}
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
template<int A, int B, int C, int D>
struct ImmChoice<A, B, C, D> {
constexpr /* implicit */ ImmChoice(int value)
{
if (value == A) {
m_encoded = 0;
} else if (value == B) {
m_encoded = 1;
} else if (value == C) {
m_encoded = 2;
} else if (value == D) {
m_encoded = 3;
} else {
throw OaknutException{ExceptionType::InvalidImmChoice};
}
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
template<unsigned Start, unsigned End>
struct ImmRange {
constexpr /* implicit */ ImmRange(unsigned value_)
: m_value(value_)
{
if (value_ < Start || value_ > End) {
throw OaknutException{ExceptionType::InvalidImmRange};
}
}
constexpr unsigned value() const { return m_value; }
private:
unsigned m_value;
};
template<std::size_t max_value>
struct LslShift {
constexpr /* implicit */ LslShift(std::size_t amount)
: m_encoded((((-amount) & (max_value - 1)) << 6) | (max_value - amount - 1))
{
if (amount >= max_value)
throw OaknutException{ExceptionType::LslShiftOutOfRange};
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
} // namespace oaknut

View file

@ -0,0 +1,82 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <tuple>
#include <type_traits>
#include "oaknut/oaknut_exception.hpp"
namespace oaknut {
struct Elem;
template<typename>
struct ElemSelector;
struct VRegArranged;
namespace detail {
template<typename>
struct is_instance_of_ElemSelector : std::false_type {};
template<typename E>
struct is_instance_of_ElemSelector<ElemSelector<E>> : std::true_type {};
template<class T>
constexpr bool is_instance_of_ElemSelector_v = is_instance_of_ElemSelector<T>::value;
struct BaseOnlyTag {};
} // namespace detail
template<typename T, std::size_t N>
struct List {
template<typename... U>
constexpr explicit List(U... args)
: m_base(std::get<0>(std::tie(args...)))
{
static_assert((std::is_same_v<T, U> && ...));
static_assert(sizeof...(args) == N);
static_assert(std::is_base_of_v<VRegArranged, T> || std::is_base_of_v<Elem, T> || detail::is_instance_of_ElemSelector_v<T>);
if (!verify(std::index_sequence_for<U...>{}, args...))
throw OaknutException{ExceptionType::InvalidList};
}
constexpr auto operator[](unsigned elem_index) const
{
using S = decltype(m_base[elem_index]);
return List<S, N>(detail::BaseOnlyTag{}, m_base[elem_index]);
}
private:
template<typename>
friend class BasicCodeGenerator;
template<typename, std::size_t>
friend struct List;
constexpr explicit List(detail::BaseOnlyTag, T base_)
: m_base(base_)
{}
template<typename... U, std::size_t... indexes>
constexpr bool verify(std::index_sequence<indexes...>, U... args)
{
if constexpr (std::is_base_of_v<VRegArranged, T>) {
return (((m_base.index() + indexes) % 32 == static_cast<std::size_t>(args.index())) && ...);
} else if constexpr (std::is_base_of_v<Elem, T>) {
return (((m_base.reg_index() + indexes) % 32 == static_cast<std::size_t>(args.reg_index()) && m_base.elem_index() == args.elem_index()) && ...);
} else {
return (((m_base.reg_index() + indexes) % 32 == static_cast<std::size_t>(args.reg_index())) && ...);
}
}
T m_base;
};
template<typename... U>
List(U...) -> List<std::common_type_t<U...>, sizeof...(U)>;
} // namespace oaknut

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,111 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
void SQRDMLAH(HReg rd, HReg rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0111111101LMmmmm1101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void SQRDMLAH(SReg rd, SReg rn, SElem em)
{
emit<"0111111110LMmmmm1101H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SQRDMLAH(VReg_4H rd, VReg_4H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0010111101LMmmmm1101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void SQRDMLAH(VReg_8H rd, VReg_8H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0110111101LMmmmm1101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void SQRDMLAH(VReg_2S rd, VReg_2S rn, SElem em)
{
emit<"0010111110LMmmmm1101H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SQRDMLAH(VReg_4S rd, VReg_4S rn, SElem em)
{
emit<"0110111110LMmmmm1101H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SQRDMLAH(HReg rd, HReg rn, HReg rm)
{
emit<"01111110010mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLAH(SReg rd, SReg rn, SReg rm)
{
emit<"01111110100mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLAH(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLAH(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLAH(VReg_2S rd, VReg_2S rn, VReg_2S rm)
{
emit<"00101110100mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLAH(VReg_4S rd, VReg_4S rn, VReg_4S rm)
{
emit<"01101110100mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLSH(HReg rd, HReg rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0111111101LMmmmm1111H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void SQRDMLSH(SReg rd, SReg rn, SElem em)
{
emit<"0111111110LMmmmm1111H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SQRDMLSH(VReg_4H rd, VReg_4H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0010111101LMmmmm1111H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void SQRDMLSH(VReg_8H rd, VReg_8H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0110111101LMmmmm1111H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void SQRDMLSH(VReg_2S rd, VReg_2S rn, SElem em)
{
emit<"0010111110LMmmmm1111H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SQRDMLSH(VReg_4S rd, VReg_4S rn, SElem em)
{
emit<"0110111110LMmmmm1111H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SQRDMLSH(HReg rd, HReg rn, HReg rm)
{
emit<"01111110010mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLSH(SReg rd, SReg rn, SReg rm)
{
emit<"01111110100mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLSH(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLSH(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLSH(VReg_2S rd, VReg_2S rn, VReg_2S rm)
{
emit<"00101110100mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SQRDMLSH(VReg_4S rd, VReg_4S rn, VReg_4S rm)
{
emit<"01101110100mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}

View file

@ -0,0 +1,855 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
void BCAX(VReg_16B rd, VReg_16B rn, VReg_16B rm, VReg_16B ra)
{
emit<"11001110001mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(rd, rn, rm, ra);
}
void EOR3(VReg_16B rd, VReg_16B rn, VReg_16B rm, VReg_16B ra)
{
emit<"11001110000mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(rd, rn, rm, ra);
}
void FABD(HReg rd, HReg rn, HReg rm)
{
emit<"01111110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FABD(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FABD(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FABS(VReg_4H rd, VReg_4H rn)
{
emit<"0000111011111000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FABS(VReg_8H rd, VReg_8H rn)
{
emit<"0100111011111000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FACGE(HReg rd, HReg rn, HReg rm)
{
emit<"01111110010mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FACGE(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FACGE(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FACGT(HReg rd, HReg rn, HReg rm)
{
emit<"01111110110mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FACGT(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110110mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FACGT(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110110mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FADD(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FADD(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FADDP(HReg rd, VReg_2H rn)
{
emit<"0101111000110000110110nnnnnddddd", "d", "n">(rd, rn);
}
void FADDP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FADDP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMEQ(HReg rd, HReg rn, HReg rm)
{
emit<"01011110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMEQ(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMEQ(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMEQ(HReg rd, HReg rn, ImmConstFZero)
{
emit<"0101111011111000110110nnnnnddddd", "d", "n">(rd, rn);
}
void FCMEQ(VReg_4H rd, VReg_4H rn, ImmConstFZero)
{
emit<"0000111011111000110110nnnnnddddd", "d", "n">(rd, rn);
}
void FCMEQ(VReg_8H rd, VReg_8H rn, ImmConstFZero)
{
emit<"0100111011111000110110nnnnnddddd", "d", "n">(rd, rn);
}
void FCMGE(HReg rd, HReg rn, HReg rm)
{
emit<"01111110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMGE(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMGE(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMGE(HReg rd, HReg rn, ImmConstFZero)
{
emit<"0111111011111000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMGE(VReg_4H rd, VReg_4H rn, ImmConstFZero)
{
emit<"0010111011111000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMGE(VReg_8H rd, VReg_8H rn, ImmConstFZero)
{
emit<"0110111011111000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMGT(HReg rd, HReg rn, HReg rm)
{
emit<"01111110110mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMGT(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110110mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMGT(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110110mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FCMGT(HReg rd, HReg rn, ImmConstFZero)
{
emit<"0101111011111000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMGT(VReg_4H rd, VReg_4H rn, ImmConstFZero)
{
emit<"0000111011111000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMGT(VReg_8H rd, VReg_8H rn, ImmConstFZero)
{
emit<"0100111011111000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMLE(HReg rd, HReg rn, ImmConstFZero)
{
emit<"0111111011111000110110nnnnnddddd", "d", "n">(rd, rn);
}
void FCMLE(VReg_4H rd, VReg_4H rn, ImmConstFZero)
{
emit<"0010111011111000110110nnnnnddddd", "d", "n">(rd, rn);
}
void FCMLE(VReg_8H rd, VReg_8H rn, ImmConstFZero)
{
emit<"0110111011111000110110nnnnnddddd", "d", "n">(rd, rn);
}
void FCMLT(HReg rd, HReg rn, ImmConstFZero)
{
emit<"0101111011111000111010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMLT(VReg_4H rd, VReg_4H rn, ImmConstFZero)
{
emit<"0000111011111000111010nnnnnddddd", "d", "n">(rd, rn);
}
void FCMLT(VReg_8H rd, VReg_8H rn, ImmConstFZero)
{
emit<"0100111011111000111010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTAS(HReg rd, HReg rn)
{
emit<"0101111001111001110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTAS(VReg_4H rd, VReg_4H rn)
{
emit<"0000111001111001110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTAS(VReg_8H rd, VReg_8H rn)
{
emit<"0100111001111001110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTAU(HReg rd, HReg rn)
{
emit<"0111111001111001110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTAU(VReg_4H rd, VReg_4H rn)
{
emit<"0010111001111001110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTAU(VReg_8H rd, VReg_8H rn)
{
emit<"0110111001111001110010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTMS(HReg rd, HReg rn)
{
emit<"0101111001111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTMS(VReg_4H rd, VReg_4H rn)
{
emit<"0000111001111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTMS(VReg_8H rd, VReg_8H rn)
{
emit<"0100111001111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTMU(HReg rd, HReg rn)
{
emit<"0111111001111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTMU(VReg_4H rd, VReg_4H rn)
{
emit<"0010111001111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTMU(VReg_8H rd, VReg_8H rn)
{
emit<"0110111001111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTNS(HReg rd, HReg rn)
{
emit<"0101111001111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTNS(VReg_4H rd, VReg_4H rn)
{
emit<"0000111001111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTNS(VReg_8H rd, VReg_8H rn)
{
emit<"0100111001111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTNU(HReg rd, HReg rn)
{
emit<"0111111001111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTNU(VReg_4H rd, VReg_4H rn)
{
emit<"0010111001111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTNU(VReg_8H rd, VReg_8H rn)
{
emit<"0110111001111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTPS(HReg rd, HReg rn)
{
emit<"0101111011111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTPS(VReg_4H rd, VReg_4H rn)
{
emit<"0000111011111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTPS(VReg_8H rd, VReg_8H rn)
{
emit<"0100111011111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTPU(HReg rd, HReg rn)
{
emit<"0111111011111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTPU(VReg_4H rd, VReg_4H rn)
{
emit<"0010111011111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTPU(VReg_8H rd, VReg_8H rn)
{
emit<"0110111011111001101010nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTZS(HReg rd, HReg rn)
{
emit<"0101111011111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTZS(VReg_4H rd, VReg_4H rn)
{
emit<"0000111011111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTZS(VReg_8H rd, VReg_8H rn)
{
emit<"0100111011111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTZU(HReg rd, HReg rn)
{
emit<"0111111011111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTZU(VReg_4H rd, VReg_4H rn)
{
emit<"0010111011111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FCVTZU(VReg_8H rd, VReg_8H rn)
{
emit<"0110111011111001101110nnnnnddddd", "d", "n">(rd, rn);
}
void FDIV(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FDIV(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAX(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAX(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAXNM(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAXNM(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAXNMP(HReg rd, VReg_2H rn)
{
emit<"0101111000110000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FMAXNMP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAXNMP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAXNMV(HReg rd, VReg_4H rn)
{
emit<"0000111000110000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FMAXNMV(HReg rd, VReg_8H rn)
{
emit<"0100111000110000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FMAXP(HReg rd, VReg_2H rn)
{
emit<"0101111000110000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FMAXP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAXP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMAXV(HReg rd, VReg_4H rn)
{
emit<"0000111000110000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FMAXV(HReg rd, VReg_8H rn)
{
emit<"0100111000110000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FMIN(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMIN(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMINNM(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMINNM(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMINNMP(HReg rd, VReg_2H rn)
{
emit<"0101111010110000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FMINNMP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMINNMP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMINNMV(HReg rd, VReg_4H rn)
{
emit<"0000111010110000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FMINNMV(HReg rd, VReg_8H rn)
{
emit<"0100111010110000110010nnnnnddddd", "d", "n">(rd, rn);
}
void FMINP(HReg rd, VReg_2H rn)
{
emit<"0101111010110000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FMINP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMINP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMINV(HReg rd, VReg_4H rn)
{
emit<"0000111010110000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FMINV(HReg rd, VReg_8H rn)
{
emit<"0100111010110000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FMLA(HReg rd, HReg rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0101111100LMmmmm0001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLA(VReg_8B rd, VReg_8B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0000111100LMmmmm0001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLA(VReg_16B rd, VReg_16B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0100111100LMmmmm0001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLA(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110010mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLA(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110010mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLAL(VReg_2S rd, VReg_2H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0000111110LMmmmm0000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLAL(VReg_4S rd, VReg_4H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0100111110LMmmmm0000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLAL2(VReg_2S rd, VReg_2H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0010111110LMmmmm1000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLAL2(VReg_4S rd, VReg_4H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0110111110LMmmmm1000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLAL(VReg_2S rd, VReg_2H rn, VReg_2H rm)
{
emit<"00001110001mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLAL(VReg_4S rd, VReg_4H rn, VReg_4H rm)
{
emit<"01001110001mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLAL2(VReg_2S rd, VReg_2H rn, VReg_2H rm)
{
emit<"00101110001mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLAL2(VReg_4S rd, VReg_4H rn, VReg_4H rm)
{
emit<"01101110001mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLS(HReg rd, HReg rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0101111100LMmmmm0101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLS(VReg_8B rd, VReg_8B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0000111100LMmmmm0101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLS(VReg_16B rd, VReg_16B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0100111100LMmmmm0101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLS(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110110mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLS(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110110mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLSL(VReg_2S rd, VReg_2H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0000111110LMmmmm0100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLSL(VReg_4S rd, VReg_4H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0100111110LMmmmm0100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLSL2(VReg_2S rd, VReg_2H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0010111110LMmmmm1100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLSL2(VReg_4S rd, VReg_4H rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0110111110LMmmmm1100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMLSL(VReg_2S rd, VReg_2H rn, VReg_2H rm)
{
emit<"00001110101mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLSL(VReg_4S rd, VReg_4H rn, VReg_4H rm)
{
emit<"01001110101mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLSL2(VReg_2S rd, VReg_2H rn, VReg_2H rm)
{
emit<"00101110101mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMLSL2(VReg_4S rd, VReg_4H rn, VReg_4H rm)
{
emit<"01101110101mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMOV(VReg_4H rd, FImm8 imm)
{
emit<"0000111100000vvv111111vvvvvddddd", "d", "v">(rd, imm);
}
void FMOV(VReg_8H rd, FImm8 imm)
{
emit<"0100111100000vvv111111vvvvvddddd", "d", "v">(rd, imm);
}
void FMUL(HReg rd, HReg rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0101111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMUL(VReg_8B rd, VReg_8B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0000111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMUL(VReg_16B rd, VReg_16B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0100111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMUL(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00101110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMUL(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01101110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMULX(HReg rd, HReg rn, HReg rm)
{
emit<"01011110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMULX(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMULX(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FMULX(HReg rd, HReg rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0111111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMULX(VReg_8B rd, VReg_8B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0010111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FMULX(VReg_16B rd, VReg_16B rn, HElem em)
{
if (em.reg_index() >= 16)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0110111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FNEG(VReg_4H rd, VReg_4H rn)
{
emit<"0010111011111000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FNEG(VReg_8H rd, VReg_8H rn)
{
emit<"0110111011111000111110nnnnnddddd", "d", "n">(rd, rn);
}
void FRECPE(HReg rd, HReg rn)
{
emit<"0101111011111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void FRECPE(VReg_4H rd, VReg_4H rn)
{
emit<"0000111011111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void FRECPE(VReg_8H rd, VReg_8H rn)
{
emit<"0100111011111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void FRECPS(HReg rd, HReg rn, HReg rm)
{
emit<"01011110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FRECPS(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FRECPS(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FRECPX(HReg rd, HReg rn)
{
emit<"0101111011111001111110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTA(VReg_4H rd, VReg_4H rn)
{
emit<"0010111001111001100010nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTA(VReg_8H rd, VReg_8H rn)
{
emit<"0110111001111001100010nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTI(VReg_4H rd, VReg_4H rn)
{
emit<"0010111011111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTI(VReg_8H rd, VReg_8H rn)
{
emit<"0110111011111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTM(VReg_4H rd, VReg_4H rn)
{
emit<"0000111001111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTM(VReg_8H rd, VReg_8H rn)
{
emit<"0100111001111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTN(VReg_4H rd, VReg_4H rn)
{
emit<"0000111001111001100010nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTN(VReg_8H rd, VReg_8H rn)
{
emit<"0100111001111001100010nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTP(VReg_4H rd, VReg_4H rn)
{
emit<"0000111011111001100010nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTP(VReg_8H rd, VReg_8H rn)
{
emit<"0100111011111001100010nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTX(VReg_4H rd, VReg_4H rn)
{
emit<"0010111001111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTX(VReg_8H rd, VReg_8H rn)
{
emit<"0110111001111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTZ(VReg_4H rd, VReg_4H rn)
{
emit<"0000111011111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRINTZ(VReg_8H rd, VReg_8H rn)
{
emit<"0100111011111001100110nnnnnddddd", "d", "n">(rd, rn);
}
void FRSQRTE(HReg rd, HReg rn)
{
emit<"0111111011111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void FRSQRTE(VReg_4H rd, VReg_4H rn)
{
emit<"0010111011111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void FRSQRTE(VReg_8H rd, VReg_8H rn)
{
emit<"0110111011111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void FRSQRTS(HReg rd, HReg rn, HReg rm)
{
emit<"01011110110mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FRSQRTS(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110110mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FRSQRTS(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110110mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FSQRT(VReg_4H rd, VReg_4H rn)
{
emit<"0010111011111001111110nnnnnddddd", "d", "n">(rd, rn);
}
void FSQRT(VReg_8H rd, VReg_8H rn)
{
emit<"0110111011111001111110nnnnnddddd", "d", "n">(rd, rn);
}
void FSUB(VReg_4H rd, VReg_4H rn, VReg_4H rm)
{
emit<"00001110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void FSUB(VReg_8H rd, VReg_8H rn, VReg_8H rm)
{
emit<"01001110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void RAX1(VReg_2D rd, VReg_2D rn, VReg_2D rm)
{
emit<"11001110011mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SCVTF(HReg rd, HReg rn)
{
emit<"0101111001111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void SCVTF(VReg_4H rd, VReg_4H rn)
{
emit<"0000111001111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void SCVTF(VReg_8H rd, VReg_8H rn)
{
emit<"0100111001111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void SDOT(VReg_2S rd, VReg_8B rn, SElem em)
{
emit<"0000111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SDOT(VReg_4S rd, VReg_16B rn, SElem em)
{
emit<"0100111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void SDOT(VReg_2S rd, VReg_8B rn, VReg_8B rm)
{
emit<"00001110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SDOT(VReg_4S rd, VReg_16B rn, VReg_16B rm)
{
emit<"01001110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SHA512H(QReg rd, QReg rn, VReg_2D rm)
{
emit<"11001110011mmmmm100000nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SHA512H2(QReg rd, QReg rn, VReg_2D rm)
{
emit<"11001110011mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SHA512SU0(VReg_2D rd, VReg_2D rn)
{
emit<"1100111011000000100000nnnnnddddd", "d", "n">(rd, rn);
}
void SHA512SU1(VReg_2D rd, VReg_2D rn, VReg_2D rm)
{
emit<"11001110011mmmmm100010nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SM3PARTW1(VReg_4S rd, VReg_4S rn, VReg_4S rm)
{
emit<"11001110011mmmmm110000nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SM3PARTW2(VReg_4S rd, VReg_4S rn, VReg_4S rm)
{
emit<"11001110011mmmmm110001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void SM3SS1(VReg_4S rd, VReg_4S rn, VReg_4S rm, VReg_4S ra)
{
emit<"11001110010mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(rd, rn, rm, ra);
}
void SM3TT1A(VReg_4S rd, VReg_4S rn, SElem em)
{
emit<"11001110010mmmmm10ii00nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
}
void SM3TT1B(VReg_4S rd, VReg_4S rn, SElem em)
{
emit<"11001110010mmmmm10ii01nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
}
void SM3TT2A(VReg_4S rd, VReg_4S rn, SElem em)
{
emit<"11001110010mmmmm10ii10nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
}
void SM3TT2B(VReg_4S rd, VReg_4S rn, SElem em)
{
emit<"11001110010mmmmm10ii11nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
}
void SM4E(VReg_4S rd, VReg_4S rn)
{
emit<"1100111011000000100001nnnnnddddd", "d", "n">(rd, rn);
}
void SM4EKEY(VReg_4S rd, VReg_4S rn, VReg_4S rm)
{
emit<"11001110011mmmmm110010nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void UCVTF(HReg rd, HReg rn)
{
emit<"0111111001111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void UCVTF(VReg_4H rd, VReg_4H rn)
{
emit<"0010111001111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void UCVTF(VReg_8H rd, VReg_8H rn)
{
emit<"0110111001111001110110nnnnnddddd", "d", "n">(rd, rn);
}
void UDOT(VReg_2S rd, VReg_8B rn, SElem em)
{
emit<"0010111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void UDOT(VReg_4S rd, VReg_16B rn, SElem em)
{
emit<"0110111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
}
void UDOT(VReg_2S rd, VReg_8B rn, VReg_8B rm)
{
emit<"00101110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void UDOT(VReg_4S rd, VReg_16B rn, VReg_16B rm)
{
emit<"01101110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
}
void XAR(VReg_2D rd, VReg_2D rn, VReg_2D rm, Imm<6> rotate_amount)
{
emit<"11001110100mmmmmiiiiiinnnnnddddd", "d", "n", "m", "i">(rd, rn, rm, rotate_amount);
}

View file

@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: Copyright (c) 2023 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
void FCADD(VReg_4H rd, VReg_4H rn, VReg_4H rm, Rot rot)
{
if (rot != Rot::DEG_90 && rot != Rot::DEG_270)
throw OaknutException{ExceptionType::InvalidRotation};
emit<"00101110010mmmmm111r01nnnnnddddd", "r", "d", "n", "m">(static_cast<std::uint32_t>(rot) >> 1, rd, rn, rm);
}
void FCADD(VReg_8H rd, VReg_8H rn, VReg_8H rm, Rot rot)
{
if (rot != Rot::DEG_90 && rot != Rot::DEG_270)
throw OaknutException{ExceptionType::InvalidRotation};
emit<"01101110010mmmmm111r01nnnnnddddd", "r", "d", "n", "m">(static_cast<std::uint32_t>(rot) >> 1, rd, rn, rm);
}
void FCADD(VReg_2S rd, VReg_2S rn, VReg_2S rm, Rot rot)
{
if (rot != Rot::DEG_90 && rot != Rot::DEG_270)
throw OaknutException{ExceptionType::InvalidRotation};
emit<"00101110100mmmmm111r01nnnnnddddd", "r", "d", "n", "m">(static_cast<std::uint32_t>(rot) >> 1, rd, rn, rm);
}
void FCADD(VReg_4S rd, VReg_4S rn, VReg_4S rm, Rot rot)
{
if (rot != Rot::DEG_90 && rot != Rot::DEG_270)
throw OaknutException{ExceptionType::InvalidRotation};
emit<"01101110100mmmmm111r01nnnnnddddd", "r", "d", "n", "m">(static_cast<std::uint32_t>(rot) >> 1, rd, rn, rm);
}
void FCADD(VReg_2D rd, VReg_2D rn, VReg_2D rm, Rot rot)
{
if (rot != Rot::DEG_90 && rot != Rot::DEG_270)
throw OaknutException{ExceptionType::InvalidRotation};
emit<"01101110110mmmmm111r01nnnnnddddd", "r", "d", "n", "m">(static_cast<std::uint32_t>(rot) >> 1, rd, rn, rm);
}
void FCMLA(VReg_4H rd, VReg_4H rn, HElem em, Rot rot)
{
if (em.reg_index() >= 16 || em.elem_index() >= 2)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0010111101LMmmmm0rr1H0nnnnnddddd", "r", "d", "n", "Mm", "H", "L">(rot, rd, rn, em.reg_index(), (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FCMLA(VReg_8H rd, VReg_8H rn, HElem em, Rot rot)
{
if (em.reg_index() >= 16 || em.elem_index() >= 4)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0110111101LMmmmm0rr1H0nnnnnddddd", "r", "d", "n", "Mm", "H", "L">(rot, rd, rn, em.reg_index(), (em.elem_index() >> 1) & 1, em.elem_index() & 1);
}
void FCMLA(VReg_4S rd, VReg_4S rn, SElem em, Rot rot)
{
if (em.reg_index() >= 16 || em.elem_index() >= 2)
throw OaknutException{ExceptionType::InvalidCombination};
emit<"0110111110LMmmmm0rr1H0nnnnnddddd", "r", "d", "n", "Mm", "H", "L">(rot, rd, rn, em.reg_index(), em.elem_index() & 1, 0);
}
void FCMLA(VReg_4H rd, VReg_4H rn, VReg_4H rm, Rot rot)
{
emit<"00101110010mmmmm110rr1nnnnnddddd", "r", "d", "n", "m">(rot, rd, rn, rm);
}
void FCMLA(VReg_8H rd, VReg_8H rn, VReg_8H rm, Rot rot)
{
emit<"01101110010mmmmm110rr1nnnnnddddd", "r", "d", "n", "m">(rot, rd, rn, rm);
}
void FCMLA(VReg_2S rd, VReg_2S rn, VReg_2S rm, Rot rot)
{
emit<"00101110100mmmmm110rr1nnnnnddddd", "r", "d", "n", "m">(rot, rd, rn, rm);
}
void FCMLA(VReg_4S rd, VReg_4S rn, VReg_4S rm, Rot rot)
{
emit<"01101110100mmmmm110rr1nnnnnddddd", "r", "d", "n", "m">(rot, rd, rn, rm);
}
void FCMLA(VReg_2D rd, VReg_2D rn, VReg_2D rm, Rot rot)
{
emit<"01101110110mmmmm110rr1nnnnnddddd", "r", "d", "n", "m">(rot, rd, rn, rm);
}
void FJCVTZS(WReg wd, DReg rn)
{
emit<"0001111001111110000000nnnnnddddd", "d", "n">(wd, rn);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
void BFC(WReg wd, Imm<5> lsb, Imm<5> width)
{
if (width.value() == 0 || width.value() > (32 - lsb.value()))
throw OaknutException{ExceptionType::InvalidBitWidth};
emit<"0011001100rrrrrrssssss11111ddddd", "d", "r", "s">(wd, (~lsb.value() + 1) & 31, width.value() - 1);
}
void BFC(XReg xd, Imm<6> lsb, Imm<6> width)
{
if (width.value() == 0 || width.value() > (64 - lsb.value()))
throw OaknutException{ExceptionType::InvalidBitWidth};
emit<"1011001101rrrrrrssssss11111ddddd", "d", "r", "s">(xd, (~lsb.value() + 1) & 63, width.value() - 1);
}
void ESB()
{
emit<"11010101000000110010001000011111">();
}
void PSB()
{
emit<"11010101000000110010001000111111">();
}

View file

@ -0,0 +1,159 @@
// SPDX-FileCopyrightText: Copyright (c) 2023 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
void AUTDA(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z110nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void AUTDB(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z111nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void AUTDZA(XReg xd)
{
emit<"110110101100000100Z11011111ddddd", "Z", "d">(1, xd);
}
void AUTDZB(XReg xd)
{
emit<"110110101100000100Z11111111ddddd", "Z", "d">(1, xd);
}
void AUTIA(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z100nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void AUTIB(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z101nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void AUTIZA(XReg xd)
{
emit<"110110101100000100Z10011111ddddd", "Z", "d">(1, xd);
}
void AUTIZB(XReg xd)
{
emit<"110110101100000100Z10111111ddddd", "Z", "d">(1, xd);
}
void BLRAA(XReg xn, XRegSp xm)
{
emit<"1101011Z0011111100001Mnnnnnmmmmm", "Z", "M", "n", "m">(1, 0, xn, xm);
}
void BLRAAZ(XReg xn)
{
emit<"1101011Z0011111100001Mnnnnn11111", "Z", "M", "n">(0, 0, xn);
}
void BLRAB(XReg xn, XRegSp xm)
{
emit<"1101011Z0011111100001Mnnnnnmmmmm", "Z", "M", "n", "m">(1, 1, xn, xm);
}
void BLRABZ(XReg xn)
{
emit<"1101011Z0011111100001Mnnnnn11111", "Z", "M", "n">(0, 1, xn);
}
void BRAA(XReg xn, XRegSp xm)
{
emit<"1101011Z0001111100001Mnnnnnmmmmm", "Z", "M", "n", "m">(1, 0, xn, xm);
}
void BRAAZ(XReg xn)
{
emit<"1101011Z0001111100001Mnnnnn11111", "Z", "M", "n">(0, 0, xn);
}
void BRAB(XReg xn, XRegSp xm)
{
emit<"1101011Z0001111100001Mnnnnnmmmmm", "Z", "M", "n", "m">(1, 1, xn, xm);
}
void BRABZ(XReg xn)
{
emit<"1101011Z0001111100001Mnnnnn11111", "Z", "M", "n">(0, 1, xn);
}
void ERETAA()
{
emit<"110101101001111100001M1111111111", "M">(0);
}
void ERETAB()
{
emit<"110101101001111100001M1111111111", "M">(1);
}
void LDAPR(WReg wt, XRegSp xn)
{
emit<"1011100010111111110000nnnnnttttt", "t", "n">(wt, xn);
}
void LDAPR(XReg xt, XRegSp xn)
{
emit<"1111100010111111110000nnnnnttttt", "t", "n">(xt, xn);
}
void LDAPRB(WReg wt, XRegSp xn)
{
emit<"0011100010111111110000nnnnnttttt", "t", "n">(wt, xn);
}
void LDAPRH(WReg wt, XRegSp xn)
{
emit<"0111100010111111110000nnnnnttttt", "t", "n">(wt, xn);
}
void LDRAA(XReg xt, XRegSp xn, SOffset<13, 3> simm = 0)
{
emit<"11111000Mi1iiiiiiiiiW1nnnnnttttt", "M", "W", "t", "n", "i">(0, 0, xt, xn, simm);
}
void LDRAB(XReg xt, XRegSp xn, SOffset<13, 3> simm = 0)
{
emit<"11111000Mi1iiiiiiiiiW1nnnnnttttt", "M", "W", "t", "n", "i">(1, 0, xt, xn, simm);
}
void LDRAA(XReg xt, XRegSp xn, PreIndexed, SOffset<13, 3> simm)
{
emit<"11111000Mi1iiiiiiiiiW1nnnnnttttt", "M", "W", "t", "n", "i">(0, 1, xt, xn, simm);
}
void LDRAB(XReg xt, XRegSp xn, PreIndexed, SOffset<13, 3> simm)
{
emit<"11111000Mi1iiiiiiiiiW1nnnnnttttt", "M", "W", "t", "n", "i">(1, 1, xt, xn, simm);
}
void PACDA(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z010nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void PACDB(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z011nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void PACDZA(XReg xd)
{
emit<"110110101100000100Z01011111ddddd", "Z", "d">(1, xd);
}
void PACDZB(XReg xd)
{
emit<"110110101100000100Z01111111ddddd", "Z", "d">(1, xd);
}
void PACGA(XReg xd, XReg xn, XRegSp xm)
{
emit<"10011010110mmmmm001100nnnnnddddd", "d", "n", "m">(xd, xn, xm);
}
void PACIA(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z000nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void PACIB(XReg xd, XRegSp xn)
{
emit<"110110101100000100Z001nnnnnddddd", "Z", "d", "n">(0, xd, xn);
}
void PACIZA(XReg xd)
{
emit<"110110101100000100Z00011111ddddd", "Z", "d">(1, xd);
}
void PACIZB(XReg xd)
{
emit<"110110101100000100Z00111111ddddd", "Z", "d">(1, xd);
}
void RETAA()
{
emit<"110101100101111100001M1111111111", "M">(0);
}
void RETAB()
{
emit<"110101100101111100001M1111111111", "M">(1);
}
void XPACD(XReg xd)
{
emit<"110110101100000101000D11111nnnnn", "D", "n">(1, xd);
}
void XPACI(XReg xd)
{
emit<"110110101100000101000D11111nnnnn", "D", "n">(0, xd);
}

View file

@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
namespace oaknut {
template<auto... Vs>
struct MultiTypedName;
template<>
struct MultiTypedName<> {};
template<auto V, auto... Vs>
struct MultiTypedName<V, Vs...> : public MultiTypedName<Vs...> {
constexpr operator decltype(V)() const { return V; }
};
} // namespace oaknut

View file

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright (c) 2023 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
// reg.hpp
OAKNUT_EXCEPTION(InvalidWSPConversion, "toW: cannot convert WSP to WReg")
OAKNUT_EXCEPTION(InvalidXSPConversion, "toX: cannot convert XSP to XReg")
OAKNUT_EXCEPTION(InvalidWZRConversion, "unexpected WZR passed into an WRegWsp")
OAKNUT_EXCEPTION(InvalidXZRConversion, "unexpected XZR passed into an XRegSp")
OAKNUT_EXCEPTION(InvalidDElem_1, "invalid DElem_1")
OAKNUT_EXCEPTION(InvalidElementIndex, "elem_index is out of range")
// imm.hpp / offset.hpp / list.hpp
OAKNUT_EXCEPTION(InvalidAddSubImm, "invalid AddSubImm")
OAKNUT_EXCEPTION(InvalidBitImm32, "invalid BitImm32")
OAKNUT_EXCEPTION(InvalidBitImm64, "invalid BitImm64")
OAKNUT_EXCEPTION(InvalidImmChoice, "invalid ImmChoice")
OAKNUT_EXCEPTION(InvalidImmConst, "invalid ImmConst")
OAKNUT_EXCEPTION(InvalidImmConstFZero, "invalid ImmConstFZero")
OAKNUT_EXCEPTION(InvalidImmRange, "invalid ImmRange")
OAKNUT_EXCEPTION(InvalidList, "invalid List")
OAKNUT_EXCEPTION(InvalidMovImm16, "invalid MovImm16")
OAKNUT_EXCEPTION(InvalidBitWidth, "invalid width")
OAKNUT_EXCEPTION(LslShiftOutOfRange, "LslShift out of range")
OAKNUT_EXCEPTION(OffsetMisaligned, "misalignment")
OAKNUT_EXCEPTION(OffsetOutOfRange, "out of range")
OAKNUT_EXCEPTION(ImmOutOfRange, "outsized Imm value")
// arm64_encode_helpers.inc.hpp
OAKNUT_EXCEPTION(InvalidAddSubExt, "invalid AddSubExt choice for rm size")
OAKNUT_EXCEPTION(InvalidIndexExt, "invalid IndexExt choice for rm size")
OAKNUT_EXCEPTION(BitPositionOutOfRange, "bit position exceeds size of rt")
OAKNUT_EXCEPTION(RequiresAbsoluteAddressesContext, "absolute addresses required")
// mnemonics_*.inc.hpp
OAKNUT_EXCEPTION(InvalidCombination, "InvalidCombination")
OAKNUT_EXCEPTION(InvalidCond, "Cond cannot be AL or NV here")
OAKNUT_EXCEPTION(InvalidPairFirst, "Requires even register")
OAKNUT_EXCEPTION(InvalidPairSecond, "Invalid second register in pair")
OAKNUT_EXCEPTION(InvalidOperandXZR, "xzr invalid here")
OAKNUT_EXCEPTION(InvalidRotation, "Invalid rotation operand")
// oaknut.hpp
OAKNUT_EXCEPTION(InvalidAlignment, "invalid alignment")
OAKNUT_EXCEPTION(LabelRedefinition, "label already resolved")

View file

@ -0,0 +1,138 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <cstdint>
#include <variant>
#include "oaknut/oaknut_exception.hpp"
namespace oaknut {
struct Label;
namespace detail {
constexpr std::uint64_t inverse_mask_from_size(std::size_t size)
{
return (~std::uint64_t{0}) << size;
}
constexpr std::uint64_t mask_from_size(std::size_t size)
{
return (~std::uint64_t{0}) >> (64 - size);
}
template<std::size_t bit_count>
constexpr std::uint64_t sign_extend(std::uint64_t value)
{
static_assert(bit_count != 0, "cannot sign-extend zero-sized value");
constexpr size_t shift_amount = 64 - bit_count;
return static_cast<std::uint64_t>(static_cast<std::int64_t>(value << shift_amount) >> shift_amount);
}
} // namespace detail
template<std::size_t bitsize, std::size_t alignment>
struct AddrOffset {
AddrOffset(std::ptrdiff_t diff)
: m_payload(encode(diff))
{}
AddrOffset(Label& label)
: m_payload(&label)
{}
AddrOffset(const void* ptr)
: m_payload(ptr)
{}
static std::uint32_t encode(std::ptrdiff_t diff)
{
const std::uint64_t diff_u64 = static_cast<std::uint64_t>(diff);
if (detail::sign_extend<bitsize>(diff_u64) != diff_u64)
throw OaknutException{ExceptionType::OffsetOutOfRange};
if (diff_u64 != (diff_u64 & detail::inverse_mask_from_size(alignment)))
throw OaknutException{ExceptionType::OffsetMisaligned};
return static_cast<std::uint32_t>((diff_u64 & detail::mask_from_size(bitsize)) >> alignment);
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::variant<std::uint32_t, Label*, const void*> m_payload;
};
template<std::size_t bitsize, std::size_t shift_amount>
struct PageOffset {
PageOffset(const void* ptr)
: m_payload(ptr)
{}
PageOffset(Label& label)
: m_payload(&label)
{}
static std::uint32_t encode(std::uintptr_t current_addr, std::uintptr_t target)
{
std::uint64_t diff = static_cast<std::uint64_t>((static_cast<std::int64_t>(target) >> shift_amount) - (static_cast<std::int64_t>(current_addr) >> shift_amount));
if (detail::sign_extend<bitsize>(diff) != diff)
throw OaknutException{ExceptionType::OffsetOutOfRange};
diff &= detail::mask_from_size(bitsize);
return static_cast<std::uint32_t>(((diff & 3) << (bitsize - 2)) | (diff >> 2));
}
static bool valid(std::uintptr_t current_addr, std::uintptr_t target)
{
std::uint64_t diff = static_cast<std::uint64_t>((static_cast<std::int64_t>(target) >> shift_amount) - (static_cast<std::int64_t>(current_addr) >> shift_amount));
return detail::sign_extend<bitsize>(diff) == diff;
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::variant<Label*, const void*> m_payload;
};
template<std::size_t bitsize, std::size_t alignment>
struct SOffset {
SOffset(std::int64_t offset)
{
const std::uint64_t diff_u64 = static_cast<std::uint64_t>(offset);
if (detail::sign_extend<bitsize>(diff_u64) != diff_u64)
throw OaknutException{ExceptionType::OffsetOutOfRange};
if (diff_u64 != (diff_u64 & detail::inverse_mask_from_size(alignment)))
throw OaknutException{ExceptionType::OffsetMisaligned};
m_encoded = static_cast<std::uint32_t>((diff_u64 & detail::mask_from_size(bitsize)) >> alignment);
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
template<std::size_t bitsize, std::size_t alignment>
struct POffset {
POffset(std::int64_t offset)
{
const std::uint64_t diff_u64 = static_cast<std::uint64_t>(offset);
if (diff_u64 > detail::mask_from_size(bitsize))
throw OaknutException{ExceptionType::OffsetOutOfRange};
if (diff_u64 != (diff_u64 & detail::inverse_mask_from_size(alignment)))
throw OaknutException{ExceptionType::OffsetMisaligned};
m_encoded = static_cast<std::uint32_t>((diff_u64 & detail::mask_from_size(bitsize)) >> alignment);
}
private:
template<typename Policy>
friend class BasicCodeGenerator;
std::uint32_t m_encoded;
};
} // namespace oaknut

View file

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright (c) 2023 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
namespace oaknut::detail {
template<class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
};
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
} // namespace oaknut::detail

View file

@ -0,0 +1,475 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
#include <cassert>
#include <cstddef>
#include <cstdint>
#include "oaknut/oaknut_exception.hpp"
namespace oaknut {
struct Reg;
struct RReg;
struct ZrReg;
struct WzrReg;
struct XReg;
struct WReg;
struct SpReg;
struct WspReg;
struct XRegSp;
struct XRegWsp;
struct VReg;
struct VRegArranged;
struct BReg;
struct HReg;
struct SReg;
struct DReg;
struct QReg;
struct VReg_2H;
struct VReg_8B;
struct VReg_4H;
struct VReg_2S;
struct VReg_1D;
struct VReg_16B;
struct VReg_8H;
struct VReg_4S;
struct VReg_2D;
struct VReg_1Q;
struct VRegSelector;
template<typename Elem>
struct ElemSelector;
struct BElem;
struct HElem;
struct SElem;
struct DElem;
struct Reg {
constexpr explicit Reg(bool is_vector_, unsigned bitsize_, int index_)
: m_index(static_cast<std::int8_t>(index_))
, m_bitsize(static_cast<std::uint8_t>(bitsize_))
, m_is_vector(is_vector_)
{
assert(index_ >= -1 && index_ <= 31);
assert(bitsize_ != 0 && (bitsize_ & (bitsize_ - 1)) == 0 && "Bitsize must be a power of two");
}
constexpr int index() const { return m_index; }
constexpr unsigned bitsize() const { return m_bitsize; }
constexpr bool is_vector() const { return m_is_vector; }
private:
std::int8_t m_index;
std::uint8_t m_bitsize;
bool m_is_vector;
};
struct RReg : public Reg {
constexpr explicit RReg(unsigned bitsize_, int index_)
: Reg(false, bitsize_, index_)
{
assert(bitsize_ == 32 || bitsize_ == 64);
}
XReg toX() const;
WReg toW() const;
template<typename Policy>
friend class BasicCodeGenerator;
};
struct ZrReg : public RReg {
constexpr explicit ZrReg()
: RReg(64, 31) {}
};
struct WzrReg : public RReg {
constexpr explicit WzrReg()
: RReg(32, 31) {}
};
struct XReg : public RReg {
constexpr explicit XReg(int index_)
: RReg(64, index_) {}
constexpr /* implicit */ XReg(ZrReg)
: RReg(64, 31) {}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct WReg : public RReg {
constexpr explicit WReg(int index_)
: RReg(32, index_) {}
constexpr /* implicit */ WReg(WzrReg)
: RReg(32, 31) {}
template<typename Policy>
friend class BasicCodeGenerator;
};
inline XReg RReg::toX() const
{
if (index() == -1)
throw OaknutException{ExceptionType::InvalidXSPConversion};
return XReg{index()};
}
inline WReg RReg::toW() const
{
if (index() == -1)
throw OaknutException{ExceptionType::InvalidWSPConversion};
return WReg{index()};
}
struct SpReg : public RReg {
constexpr explicit SpReg()
: RReg(64, -1) {}
};
struct WspReg : public RReg {
constexpr explicit WspReg()
: RReg(64, -1) {}
};
struct XRegSp : public RReg {
constexpr /* implict */ XRegSp(SpReg)
: RReg(64, -1) {}
constexpr /* implict */ XRegSp(XReg xr)
: RReg(64, xr.index())
{
if (xr.index() == 31)
throw OaknutException{ExceptionType::InvalidXZRConversion};
}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct WRegWsp : public RReg {
constexpr /* implict */ WRegWsp(WspReg)
: RReg(32, -1) {}
constexpr /* implict */ WRegWsp(WReg wr)
: RReg(32, wr.index())
{
if (wr.index() == 31)
throw OaknutException{ExceptionType::InvalidWZRConversion};
}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg : public Reg {
constexpr explicit VReg(unsigned bitsize_, int index_)
: Reg(true, bitsize_, index_)
{
assert(bitsize_ == 8 || bitsize_ == 16 || bitsize_ == 32 || bitsize_ == 64 || bitsize_ == 128);
}
constexpr BReg toB() const;
constexpr HReg toH() const;
constexpr SReg toS() const;
constexpr DReg toD() const;
constexpr QReg toQ() const;
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VRegArranged : public Reg {
protected:
constexpr explicit VRegArranged(unsigned bitsize_, int index_, unsigned esize_)
: Reg(true, bitsize_, index_), m_esize(static_cast<std::uint8_t>(esize_))
{
assert(esize_ != 0 && (esize_ & (esize_ - 1)) == 0 && "esize must be a power of two");
assert(esize_ <= bitsize_);
}
template<typename Policy>
friend class BasicCodeGenerator;
private:
std::uint8_t m_esize;
};
struct VReg_2H : public VRegArranged {
constexpr explicit VReg_2H(int reg_index_)
: VRegArranged(32, reg_index_, 32 / 2)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_8B : public VRegArranged {
constexpr explicit VReg_8B(int reg_index_)
: VRegArranged(64, reg_index_, 64 / 8)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_4H : public VRegArranged {
constexpr explicit VReg_4H(int reg_index_)
: VRegArranged(64, reg_index_, 64 / 4)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_2S : public VRegArranged {
constexpr explicit VReg_2S(int reg_index_)
: VRegArranged(64, reg_index_, 64 / 2)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_1D : public VRegArranged {
constexpr explicit VReg_1D(int reg_index_)
: VRegArranged(64, reg_index_, 64 / 1)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_16B : public VRegArranged {
constexpr explicit VReg_16B(int reg_index_)
: VRegArranged(128, reg_index_, 128 / 16)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_8H : public VRegArranged {
constexpr explicit VReg_8H(int reg_index_)
: VRegArranged(128, reg_index_, 128 / 8)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_4S : public VRegArranged {
constexpr explicit VReg_4S(int reg_index_)
: VRegArranged(128, reg_index_, 128 / 4)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_2D : public VRegArranged {
constexpr explicit VReg_2D(int reg_index_)
: VRegArranged(128, reg_index_, 128 / 2)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct VReg_1Q : public VRegArranged {
constexpr explicit VReg_1Q(int reg_index_)
: VRegArranged(128, reg_index_, 128 / 1)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct Elem {
constexpr explicit Elem(unsigned esize_, int reg_, unsigned elem_index_)
: m_esize(esize_), m_reg(reg_), m_elem_index(elem_index_)
{
if (elem_index_ >= 128 / esize_)
throw OaknutException{ExceptionType::InvalidElementIndex};
}
constexpr unsigned esize() const { return m_esize; }
constexpr int reg_index() const { return m_reg; }
constexpr unsigned elem_index() const { return m_elem_index; }
private:
unsigned m_esize;
int m_reg;
unsigned m_elem_index;
};
struct BElem : public Elem {
constexpr explicit BElem(int reg_, unsigned elem_index_)
: Elem(2, reg_, elem_index_)
{}
};
struct HElem : public Elem {
constexpr explicit HElem(int reg_, unsigned elem_index_)
: Elem(2, reg_, elem_index_)
{}
};
struct SElem : public Elem {
constexpr explicit SElem(int reg_, unsigned elem_index_)
: Elem(4, reg_, elem_index_)
{}
};
struct DElem : public Elem {
constexpr explicit DElem(int reg_, unsigned elem_index_)
: Elem(8, reg_, elem_index_)
{}
};
struct DElem_1 : public DElem {
constexpr /* implict */ DElem_1(DElem inner)
: DElem(inner)
{
if (inner.elem_index() != 1)
throw OaknutException{ExceptionType::InvalidDElem_1};
}
};
template<typename E>
struct ElemSelector {
constexpr explicit ElemSelector(int reg_index_)
: m_reg_index(reg_index_)
{}
constexpr int reg_index() const { return m_reg_index; }
constexpr E operator[](unsigned elem_index) const { return E{m_reg_index, elem_index}; }
private:
int m_reg_index;
};
struct BReg : public VReg {
constexpr explicit BReg(int index_)
: VReg(8, index_)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct HReg : public VReg {
constexpr explicit HReg(int index_)
: VReg(16, index_)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct SReg : public VReg {
constexpr explicit SReg(int index_)
: VReg(32, index_)
{}
template<typename Policy>
friend class BasicCodeGenerator;
};
struct DReg : public VReg {
constexpr explicit DReg(int index_)
: VReg(64, index_)
{}
template<typename Policy>
friend class BasicCodeGenerator;
constexpr ElemSelector<BElem> Belem() const { return ElemSelector<BElem>(index()); }
constexpr ElemSelector<HElem> Helem() const { return ElemSelector<HElem>(index()); }
constexpr ElemSelector<SElem> Selem() const { return ElemSelector<SElem>(index()); }
constexpr ElemSelector<DElem> Delem() const { return ElemSelector<DElem>(index()); }
constexpr VReg_8B B8() const { return VReg_8B{index()}; }
constexpr VReg_4H H4() const { return VReg_4H{index()}; }
constexpr VReg_2S S2() const { return VReg_2S{index()}; }
constexpr VReg_1D D1() const { return VReg_1D{index()}; }
};
struct QReg : public VReg {
constexpr explicit QReg(int index_)
: VReg(128, index_)
{}
template<typename Policy>
friend class BasicCodeGenerator;
constexpr ElemSelector<BElem> Belem() const { return ElemSelector<BElem>(index()); }
constexpr ElemSelector<HElem> Helem() const { return ElemSelector<HElem>(index()); }
constexpr ElemSelector<SElem> Selem() const { return ElemSelector<SElem>(index()); }
constexpr ElemSelector<DElem> Delem() const { return ElemSelector<DElem>(index()); }
constexpr VReg_16B B16() const { return VReg_16B{index()}; }
constexpr VReg_8H H8() const { return VReg_8H{index()}; }
constexpr VReg_4S S4() const { return VReg_4S{index()}; }
constexpr VReg_2D D2() const { return VReg_2D{index()}; }
constexpr VReg_1Q Q1() const { return VReg_1Q{index()}; }
};
constexpr BReg VReg::toB() const
{
return BReg{index()};
}
constexpr HReg VReg::toH() const
{
return HReg{index()};
}
constexpr SReg VReg::toS() const
{
return SReg{index()};
}
constexpr DReg VReg::toD() const
{
return DReg{index()};
}
constexpr QReg VReg::toQ() const
{
return QReg{index()};
}
struct VRegSelector {
constexpr explicit VRegSelector(int reg_index)
: m_reg_index(reg_index)
{}
constexpr int index() const { return m_reg_index; }
constexpr ElemSelector<BElem> B() const { return ElemSelector<BElem>(index()); }
constexpr ElemSelector<HElem> H() const { return ElemSelector<HElem>(index()); }
constexpr ElemSelector<SElem> S() const { return ElemSelector<SElem>(index()); }
constexpr ElemSelector<DElem> D() const { return ElemSelector<DElem>(index()); }
constexpr VReg_2H H2() const { return VReg_2H{index()}; }
constexpr VReg_8B B8() const { return VReg_8B{index()}; }
constexpr VReg_4H H4() const { return VReg_4H{index()}; }
constexpr VReg_2S S2() const { return VReg_2S{index()}; }
constexpr VReg_1D D1() const { return VReg_1D{index()}; }
constexpr VReg_16B B16() const { return VReg_16B{index()}; }
constexpr VReg_8H H8() const { return VReg_8H{index()}; }
constexpr VReg_4S S4() const { return VReg_4S{index()}; }
constexpr VReg_2D D2() const { return VReg_2D{index()}; }
constexpr VReg_1Q Q1() const { return VReg_1Q{index()}; }
private:
int m_reg_index;
};
} // namespace oaknut

View file

@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#pragma once
#include <algorithm>
#include <cstddef>
namespace oaknut {
template<size_t N>
struct StringLiteral {
constexpr StringLiteral(const char (&str)[N])
{
std::copy_n(str, N, value);
}
static constexpr std::size_t strlen = N - 1;
static constexpr std::size_t size = N;
char value[N];
};
namespace detail {
template<StringLiteral<33> haystack, StringLiteral needles>
consteval std::uint32_t find()
{
std::uint32_t result = 0;
for (std::size_t i = 0; i < 32; i++) {
for (std::size_t a = 0; a < needles.strlen; a++) {
if (haystack.value[i] == needles.value[a]) {
result |= 1 << (31 - i);
}
}
}
return result;
}
} // namespace detail
} // namespace oaknut