99c0a73f91
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
475 lines
12 KiB
C++
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
|