registers.hpp
1 #pragma once 2 3 #include <biscuit/assert.hpp> 4 5 #include <compare> 6 #include <cstdint> 7 8 namespace biscuit { 9 10 /** 11 * Generic abstraction around a register. 12 * 13 * This is less bug-prone than using raw primitive sizes 14 * in opcode emitter functions, since it provides stronger typing. 15 */ 16 class Register { 17 public: 18 constexpr Register() noexcept = default; 19 20 /// Gets the index for this register. 21 [[nodiscard]] constexpr uint32_t Index() const noexcept { 22 return m_index; 23 } 24 25 friend constexpr bool operator==(Register, Register) = default; 26 friend constexpr auto operator<=>(Register, Register) = default; 27 28 protected: 29 constexpr explicit Register(uint32_t index) noexcept 30 : m_index{index} {} 31 32 private: 33 uint32_t m_index{}; 34 }; 35 36 /// General purpose register. 37 class GPR final : public Register { 38 public: 39 constexpr GPR() noexcept : Register{0} {} 40 constexpr explicit GPR(uint32_t index) noexcept : Register{index} {} 41 42 friend constexpr bool operator==(GPR, GPR) = default; 43 friend constexpr auto operator<=>(GPR, GPR) = default; 44 }; 45 46 /// Floating point register. 47 class FPR final : public Register { 48 public: 49 constexpr FPR() noexcept : Register{0} {} 50 constexpr explicit FPR(uint32_t index) noexcept : Register{index} {} 51 52 friend constexpr bool operator==(FPR, FPR) = default; 53 friend constexpr auto operator<=>(FPR, FPR) = default; 54 }; 55 56 /// Vector register. 57 class Vec final : public Register { 58 public: 59 constexpr Vec() noexcept : Register{0} {} 60 constexpr explicit Vec(uint32_t index) noexcept : Register{index} {} 61 62 friend constexpr bool operator==(Vec, Vec) = default; 63 friend constexpr auto operator<=>(Vec, Vec) = default; 64 }; 65 66 // General-purpose Registers 67 68 constexpr GPR x0{0}; 69 constexpr GPR x1{1}; 70 constexpr GPR x2{2}; 71 constexpr GPR x3{3}; 72 constexpr GPR x4{4}; 73 constexpr GPR x5{5}; 74 constexpr GPR x6{6}; 75 constexpr GPR x7{7}; 76 constexpr GPR x8{8}; 77 constexpr GPR x9{9}; 78 constexpr GPR x10{10}; 79 constexpr GPR x11{11}; 80 constexpr GPR x12{12}; 81 constexpr GPR x13{13}; 82 constexpr GPR x14{14}; 83 constexpr GPR x15{15}; 84 constexpr GPR x16{16}; 85 constexpr GPR x17{17}; 86 constexpr GPR x18{18}; 87 constexpr GPR x19{19}; 88 constexpr GPR x20{20}; 89 constexpr GPR x21{21}; 90 constexpr GPR x22{22}; 91 constexpr GPR x23{23}; 92 constexpr GPR x24{24}; 93 constexpr GPR x25{25}; 94 constexpr GPR x26{26}; 95 constexpr GPR x27{27}; 96 constexpr GPR x28{28}; 97 constexpr GPR x29{29}; 98 constexpr GPR x30{30}; 99 constexpr GPR x31{31}; 100 101 // Symbolic General-purpose Register Names 102 103 constexpr GPR zero{x0}; 104 105 constexpr GPR ra{x1}; 106 constexpr GPR sp{x2}; 107 constexpr GPR gp{x3}; 108 constexpr GPR tp{x4}; 109 constexpr GPR fp{x8}; 110 111 constexpr GPR a0{x10}; 112 constexpr GPR a1{x11}; 113 constexpr GPR a2{x12}; 114 constexpr GPR a3{x13}; 115 constexpr GPR a4{x14}; 116 constexpr GPR a5{x15}; 117 constexpr GPR a6{x16}; 118 constexpr GPR a7{x17}; 119 120 constexpr GPR s0{x8}; 121 constexpr GPR s1{x9}; 122 constexpr GPR s2{x18}; 123 constexpr GPR s3{x19}; 124 constexpr GPR s4{x20}; 125 constexpr GPR s5{x21}; 126 constexpr GPR s6{x22}; 127 constexpr GPR s7{x23}; 128 constexpr GPR s8{x24}; 129 constexpr GPR s9{x25}; 130 constexpr GPR s10{x26}; 131 constexpr GPR s11{x27}; 132 133 constexpr GPR t0{x5}; 134 constexpr GPR t1{x6}; 135 constexpr GPR t2{x7}; 136 constexpr GPR t3{x28}; 137 constexpr GPR t4{x29}; 138 constexpr GPR t5{x30}; 139 constexpr GPR t6{x31}; 140 141 // Floating-point registers 142 143 constexpr FPR f0{0}; 144 constexpr FPR f1{1}; 145 constexpr FPR f2{2}; 146 constexpr FPR f3{3}; 147 constexpr FPR f4{4}; 148 constexpr FPR f5{5}; 149 constexpr FPR f6{6}; 150 constexpr FPR f7{7}; 151 constexpr FPR f8{8}; 152 constexpr FPR f9{9}; 153 constexpr FPR f10{10}; 154 constexpr FPR f11{11}; 155 constexpr FPR f12{12}; 156 constexpr FPR f13{13}; 157 constexpr FPR f14{14}; 158 constexpr FPR f15{15}; 159 constexpr FPR f16{16}; 160 constexpr FPR f17{17}; 161 constexpr FPR f18{18}; 162 constexpr FPR f19{19}; 163 constexpr FPR f20{20}; 164 constexpr FPR f21{21}; 165 constexpr FPR f22{22}; 166 constexpr FPR f23{23}; 167 constexpr FPR f24{24}; 168 constexpr FPR f25{25}; 169 constexpr FPR f26{26}; 170 constexpr FPR f27{27}; 171 constexpr FPR f28{28}; 172 constexpr FPR f29{29}; 173 constexpr FPR f30{30}; 174 constexpr FPR f31{31}; 175 176 // Symbolic Floating-point Register Names 177 178 constexpr FPR fa0{f10}; 179 constexpr FPR fa1{f11}; 180 constexpr FPR fa2{f12}; 181 constexpr FPR fa3{f13}; 182 constexpr FPR fa4{f14}; 183 constexpr FPR fa5{f15}; 184 constexpr FPR fa6{f16}; 185 constexpr FPR fa7{f17}; 186 187 constexpr FPR ft0{f0}; 188 constexpr FPR ft1{f1}; 189 constexpr FPR ft2{f2}; 190 constexpr FPR ft3{f3}; 191 constexpr FPR ft4{f4}; 192 constexpr FPR ft5{f5}; 193 constexpr FPR ft6{f6}; 194 constexpr FPR ft7{f7}; 195 constexpr FPR ft8{f28}; 196 constexpr FPR ft9{f29}; 197 constexpr FPR ft10{f30}; 198 constexpr FPR ft11{f31}; 199 200 constexpr FPR fs0{f8}; 201 constexpr FPR fs1{f9}; 202 constexpr FPR fs2{f18}; 203 constexpr FPR fs3{f19}; 204 constexpr FPR fs4{f20}; 205 constexpr FPR fs5{f21}; 206 constexpr FPR fs6{f22}; 207 constexpr FPR fs7{f23}; 208 constexpr FPR fs8{f24}; 209 constexpr FPR fs9{f25}; 210 constexpr FPR fs10{f26}; 211 constexpr FPR fs11{f27}; 212 213 // Vector registers (V extension) 214 215 constexpr Vec v0{0}; 216 constexpr Vec v1{1}; 217 constexpr Vec v2{2}; 218 constexpr Vec v3{3}; 219 constexpr Vec v4{4}; 220 constexpr Vec v5{5}; 221 constexpr Vec v6{6}; 222 constexpr Vec v7{7}; 223 constexpr Vec v8{8}; 224 constexpr Vec v9{9}; 225 constexpr Vec v10{10}; 226 constexpr Vec v11{11}; 227 constexpr Vec v12{12}; 228 constexpr Vec v13{13}; 229 constexpr Vec v14{14}; 230 constexpr Vec v15{15}; 231 constexpr Vec v16{16}; 232 constexpr Vec v17{17}; 233 constexpr Vec v18{18}; 234 constexpr Vec v19{19}; 235 constexpr Vec v20{20}; 236 constexpr Vec v21{21}; 237 constexpr Vec v22{22}; 238 constexpr Vec v23{23}; 239 constexpr Vec v24{24}; 240 constexpr Vec v25{25}; 241 constexpr Vec v26{26}; 242 constexpr Vec v27{27}; 243 constexpr Vec v28{28}; 244 constexpr Vec v29{29}; 245 constexpr Vec v30{30}; 246 constexpr Vec v31{31}; 247 248 // Register utilities 249 250 // Used with compressed stack management instructions 251 // (cm.push, cm.pop, etc) for building up a register list to encode. 252 // 253 // Also enforces that only valid registers are used in the lists. 254 class PushPopList final { 255 public: 256 // Represents an inclusive range ([start, end]) of registers. 257 struct Range final { 258 // Signifies an empty range. Normally this doesn't need to explicitly 259 // be created. Default parameters will usually take care of it. 260 constexpr Range() : start{UINT32_MAX}, end{UINT32_MAX} {} 261 262 // This particular constructor is used for the case of rlist=5 263 // where only ra and s0 get stored. 264 constexpr Range(GPR start_end) noexcept : start{start_end}, end{start_end} { 265 BISCUIT_ASSERT(start_end == s0); 266 } 267 268 constexpr Range(GPR start_, GPR end_) noexcept : start{start_}, end{end_} { 269 BISCUIT_ASSERT(start_ == s0); 270 BISCUIT_ASSERT(IsSRegister(end_)); 271 272 // See the Zc spec. The only way for s10 to be used is to also include s11. 273 BISCUIT_ASSERT(end_ != s10); 274 } 275 276 GPR start; 277 GPR end; 278 }; 279 280 // Deliberately non-explicit to allow for convenient instantiation at usage sites. 281 // e.g. Rather than CM.POP(PushPopList{ra, {s0, s2}}, 16), we can just have the 282 // usage be transparent like CM.POP({ra, {s0, s2}}, 16). Nice and compact! 283 constexpr PushPopList(GPR ra_reg, const Range& range = {}) noexcept 284 : m_bitmask{BuildBitmask(range)} { 285 BISCUIT_ASSERT(ra_reg == ra); 286 } 287 288 // Gets the built-up bitmask of passed in registers 289 [[nodiscard]] constexpr uint32_t GetBitmask() const noexcept { 290 return m_bitmask; 291 } 292 293 private: 294 [[nodiscard]] static constexpr uint32_t BuildBitmask(const Range& range) noexcept { 295 if (range.end.Index() == UINT32_MAX) { 296 return 4U; 297 } 298 if (range.end == s11) { 299 return 15U; 300 } 301 if (range.end == s0 || range.end == s1) { 302 return range.end.Index() - 3U; 303 } 304 return range.end.Index() - 11U; 305 } 306 307 // Aside from ra, it's only valid for s0-s11 to show up the register list ranges. 308 [[nodiscard]] static constexpr bool IsSRegister(const GPR gpr) noexcept { 309 return gpr == s0 || gpr == s1 || (gpr >= s2 && gpr <= s11); 310 } 311 312 uint32_t m_bitmask = 0; 313 }; 314 315 } // namespace biscuit