dynarmic/include/biscuit/registers.hpp
Merry e4a733d5b2 Squashed 'externals/biscuit/' content from commit 1d53c9e6
git-subtree-dir: externals/biscuit
git-subtree-split: 1d53c9e6cfe56544982200a5bac15a5de064936b
2024-03-02 19:36:24 +00:00

315 lines
7.8 KiB
C++

#pragma once
#include <biscuit/assert.hpp>
#include <compare>
#include <cstdint>
namespace biscuit {
/**
* Generic abstraction around a register.
*
* This is less bug-prone than using raw primitive sizes
* in opcode emitter functions, since it provides stronger typing.
*/
class Register {
public:
constexpr Register() noexcept = default;
/// Gets the index for this register.
[[nodiscard]] constexpr uint32_t Index() const noexcept {
return m_index;
}
friend constexpr bool operator==(Register, Register) = default;
friend constexpr auto operator<=>(Register, Register) = default;
protected:
constexpr explicit Register(uint32_t index) noexcept
: m_index{index} {}
private:
uint32_t m_index{};
};
/// General purpose register.
class GPR final : public Register {
public:
constexpr GPR() noexcept : Register{0} {}
constexpr explicit GPR(uint32_t index) noexcept : Register{index} {}
friend constexpr bool operator==(GPR, GPR) = default;
friend constexpr auto operator<=>(GPR, GPR) = default;
};
/// Floating point register.
class FPR final : public Register {
public:
constexpr FPR() noexcept : Register{0} {}
constexpr explicit FPR(uint32_t index) noexcept : Register{index} {}
friend constexpr bool operator==(FPR, FPR) = default;
friend constexpr auto operator<=>(FPR, FPR) = default;
};
/// Vector register.
class Vec final : public Register {
public:
constexpr Vec() noexcept : Register{0} {}
constexpr explicit Vec(uint32_t index) noexcept : Register{index} {}
friend constexpr bool operator==(Vec, Vec) = default;
friend constexpr auto operator<=>(Vec, Vec) = default;
};
// General-purpose Registers
constexpr GPR x0{0};
constexpr GPR x1{1};
constexpr GPR x2{2};
constexpr GPR x3{3};
constexpr GPR x4{4};
constexpr GPR x5{5};
constexpr GPR x6{6};
constexpr GPR x7{7};
constexpr GPR x8{8};
constexpr GPR x9{9};
constexpr GPR x10{10};
constexpr GPR x11{11};
constexpr GPR x12{12};
constexpr GPR x13{13};
constexpr GPR x14{14};
constexpr GPR x15{15};
constexpr GPR x16{16};
constexpr GPR x17{17};
constexpr GPR x18{18};
constexpr GPR x19{19};
constexpr GPR x20{20};
constexpr GPR x21{21};
constexpr GPR x22{22};
constexpr GPR x23{23};
constexpr GPR x24{24};
constexpr GPR x25{25};
constexpr GPR x26{26};
constexpr GPR x27{27};
constexpr GPR x28{28};
constexpr GPR x29{29};
constexpr GPR x30{30};
constexpr GPR x31{31};
// Symbolic General-purpose Register Names
constexpr GPR zero{x0};
constexpr GPR ra{x1};
constexpr GPR sp{x2};
constexpr GPR gp{x3};
constexpr GPR tp{x4};
constexpr GPR fp{x8};
constexpr GPR a0{x10};
constexpr GPR a1{x11};
constexpr GPR a2{x12};
constexpr GPR a3{x13};
constexpr GPR a4{x14};
constexpr GPR a5{x15};
constexpr GPR a6{x16};
constexpr GPR a7{x17};
constexpr GPR s0{x8};
constexpr GPR s1{x9};
constexpr GPR s2{x18};
constexpr GPR s3{x19};
constexpr GPR s4{x20};
constexpr GPR s5{x21};
constexpr GPR s6{x22};
constexpr GPR s7{x23};
constexpr GPR s8{x24};
constexpr GPR s9{x25};
constexpr GPR s10{x26};
constexpr GPR s11{x27};
constexpr GPR t0{x5};
constexpr GPR t1{x6};
constexpr GPR t2{x7};
constexpr GPR t3{x28};
constexpr GPR t4{x29};
constexpr GPR t5{x30};
constexpr GPR t6{x31};
// Floating-point registers
constexpr FPR f0{0};
constexpr FPR f1{1};
constexpr FPR f2{2};
constexpr FPR f3{3};
constexpr FPR f4{4};
constexpr FPR f5{5};
constexpr FPR f6{6};
constexpr FPR f7{7};
constexpr FPR f8{8};
constexpr FPR f9{9};
constexpr FPR f10{10};
constexpr FPR f11{11};
constexpr FPR f12{12};
constexpr FPR f13{13};
constexpr FPR f14{14};
constexpr FPR f15{15};
constexpr FPR f16{16};
constexpr FPR f17{17};
constexpr FPR f18{18};
constexpr FPR f19{19};
constexpr FPR f20{20};
constexpr FPR f21{21};
constexpr FPR f22{22};
constexpr FPR f23{23};
constexpr FPR f24{24};
constexpr FPR f25{25};
constexpr FPR f26{26};
constexpr FPR f27{27};
constexpr FPR f28{28};
constexpr FPR f29{29};
constexpr FPR f30{30};
constexpr FPR f31{31};
// Symbolic Floating-point Register Names
constexpr FPR fa0{f10};
constexpr FPR fa1{f11};
constexpr FPR fa2{f12};
constexpr FPR fa3{f13};
constexpr FPR fa4{f14};
constexpr FPR fa5{f15};
constexpr FPR fa6{f16};
constexpr FPR fa7{f17};
constexpr FPR ft0{f0};
constexpr FPR ft1{f1};
constexpr FPR ft2{f2};
constexpr FPR ft3{f3};
constexpr FPR ft4{f4};
constexpr FPR ft5{f5};
constexpr FPR ft6{f6};
constexpr FPR ft7{f7};
constexpr FPR ft8{f28};
constexpr FPR ft9{f29};
constexpr FPR ft10{f30};
constexpr FPR ft11{f31};
constexpr FPR fs0{f8};
constexpr FPR fs1{f9};
constexpr FPR fs2{f18};
constexpr FPR fs3{f19};
constexpr FPR fs4{f20};
constexpr FPR fs5{f21};
constexpr FPR fs6{f22};
constexpr FPR fs7{f23};
constexpr FPR fs8{f24};
constexpr FPR fs9{f25};
constexpr FPR fs10{f26};
constexpr FPR fs11{f27};
// Vector registers (V extension)
constexpr Vec v0{0};
constexpr Vec v1{1};
constexpr Vec v2{2};
constexpr Vec v3{3};
constexpr Vec v4{4};
constexpr Vec v5{5};
constexpr Vec v6{6};
constexpr Vec v7{7};
constexpr Vec v8{8};
constexpr Vec v9{9};
constexpr Vec v10{10};
constexpr Vec v11{11};
constexpr Vec v12{12};
constexpr Vec v13{13};
constexpr Vec v14{14};
constexpr Vec v15{15};
constexpr Vec v16{16};
constexpr Vec v17{17};
constexpr Vec v18{18};
constexpr Vec v19{19};
constexpr Vec v20{20};
constexpr Vec v21{21};
constexpr Vec v22{22};
constexpr Vec v23{23};
constexpr Vec v24{24};
constexpr Vec v25{25};
constexpr Vec v26{26};
constexpr Vec v27{27};
constexpr Vec v28{28};
constexpr Vec v29{29};
constexpr Vec v30{30};
constexpr Vec v31{31};
// Register utilities
// Used with compressed stack management instructions
// (cm.push, cm.pop, etc) for building up a register list to encode.
//
// Also enforces that only valid registers are used in the lists.
class PushPopList final {
public:
// Represents an inclusive range ([start, end]) of registers.
struct Range final {
// Signifies an empty range. Normally this doesn't need to explicitly
// be created. Default parameters will usually take care of it.
constexpr Range() : start{UINT32_MAX}, end{UINT32_MAX} {}
// This particular constructor is used for the case of rlist=5
// where only ra and s0 get stored.
constexpr Range(GPR start_end) noexcept : start{start_end}, end{start_end} {
BISCUIT_ASSERT(start_end == s0);
}
constexpr Range(GPR start_, GPR end_) noexcept : start{start_}, end{end_} {
BISCUIT_ASSERT(start_ == s0);
BISCUIT_ASSERT(IsSRegister(end_));
// See the Zc spec. The only way for s10 to be used is to also include s11.
BISCUIT_ASSERT(end_ != s10);
}
GPR start;
GPR end;
};
// Deliberately non-explicit to allow for convenient instantiation at usage sites.
// e.g. Rather than CM.POP(PushPopList{ra, {s0, s2}}, 16), we can just have the
// usage be transparent like CM.POP({ra, {s0, s2}}, 16). Nice and compact!
constexpr PushPopList(GPR ra_reg, const Range& range = {}) noexcept
: m_bitmask{BuildBitmask(range)} {
BISCUIT_ASSERT(ra_reg == ra);
}
// Gets the built-up bitmask of passed in registers
[[nodiscard]] constexpr uint32_t GetBitmask() const noexcept {
return m_bitmask;
}
private:
[[nodiscard]] static constexpr uint32_t BuildBitmask(const Range& range) noexcept {
if (range.end.Index() == UINT32_MAX) {
return 4U;
}
if (range.end == s11) {
return 15U;
}
if (range.end == s0 || range.end == s1) {
return range.end.Index() - 3U;
}
return range.end.Index() - 11U;
}
// Aside from ra, it's only valid for s0-s11 to show up the register list ranges.
[[nodiscard]] static constexpr bool IsSRegister(const GPR gpr) noexcept {
return gpr == s0 || gpr == s1 || (gpr >= s2 && gpr <= s11);
}
uint32_t m_bitmask = 0;
};
} // namespace biscuit