dynarmic/include/oaknut/impl/reg.hpp
Merry 99c0a73f91 Squashed 'externals/oaknut/' changes from c24f918e5..d0488d932
d0488d932 oaknut: 2.0.0
40ad78bbf oaknut: Implement DualCodeBlock and related support
9f131cfb5 oaknut: add configuration for standalone installation
69799b43c oaknut: Test building for Android on CI
1d51f5512 oaknut: 1.2.2
918bd94f0 oaknut: Eliminate -Wconversion warnings
316d8869e oaknut: Fix edgecases in MOVP2R on +/-4GiB boundary
d8634eaa1 oaknut: Fix page boundary error in ADP
d0ca9a24e oaknut: Update README examples for CPU feature detection
dbeec268b oaknut: feature_detection_freebsd: Warn about incompatibility with earlier FreeBSD versions
86e5386e2 oaknut: feature_detect: Support NetBSD
df4cf2d48 oaknut: feature_detect: Support OpenBSD
99dfff25a oaknut: feature_detection: Read ID registers
319b3d2c9 oaknut: Add basic CPU feature detection
23e9ddb4c oaknut: CI: Don't run slow tests on OpenBSD
734f1bdb4 oaknut: CI: Use up-to-date qemu
f462c9774 oaknut: CI: Build on OpenBSD
19cd42204 oaknut: code_block: Add NetBSD and OpenBSD support
18b86a3ec oaknut: SystemReg: Add more EL0 accessible registers
53c43bf0c oaknut/tests: Reduce iterations for MOVP2R
cc37df19e oaknut: Test on FreeBSD
a66b32d26 oaknut: Fix crossing sign boundary in PageOffset
206468d72 oaknut: CI: Add macos-arm64 build
e6eecc3f9 oaknut: 1.2.1
4252d8f4a oaknut: CMakeLists: Warnings are errors on MSVC
408eed65f oaknut: arm64_encode_helpers: remove unreachable code
bfc8eedfb oaknut: arm64_encode_helpers: p maybe unused
ff4456eca oaknut: Avoid negation of unsigned values
b4ac8fd6c oaknut: Fix MOV for applications of MOVN
0575cadc4 oaknut: Disable certain functionality where absolute addressing is not available
394a3c8f0 oaknut: Appease MSVC
011183670 oaknut: 1.2.0
e83c9f327 oaknut: Add VectorCodeGenerator
5eb122cc5 oaknut: Tidy up public header
45c5a7b25 oaknut: Fix clang-format errors
36243256f oaknut: Add `const` qualifier to `AddrOffset` ctor
4af500cb5 oaknut: Add `ptr` accessor to `Label`
bccb06669 oaknut: CodeGenerator const correctness
da0590a86 oaknut: github: Update package repositories

git-subtree-dir: externals/oaknut
git-subtree-split: d0488d9320ae673167dd9117223e3453d5ff102f
2024-01-28 14:56:59 +00:00

475 lines
12 KiB
C++

// 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