/ externals / biscuit / include / biscuit / registers.hpp
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