Skip to main content

ab_riscv_primitives/registers/
general_purpose.rs

1//! RISC-V general purpose registers
2
3#[cfg(test)]
4mod tests;
5
6use crate::registers::general_purpose::private::PhantomRegister;
7use core::fmt;
8use core::hint::unreachable_unchecked;
9use core::marker::Destruct;
10use core::ops::{Add, AddAssign, Sub, SubAssign};
11
12mod private {
13    use core::marker::PhantomData;
14
15    #[derive(Debug, Clone, Copy)]
16    pub struct PhantomRegister<Type>(PhantomData<Type>);
17}
18
19/// General purpose register
20///
21/// # Safety
22/// `Self::offset()` must return values in `0..Self::N` range.
23pub const unsafe trait Register:
24    fmt::Display + fmt::Debug + [const] Eq + [const] Destruct + Copy + Sized
25{
26    /// The number of general purpose registers.
27    ///
28    /// Canonically 32 unless E extension is used, in which case 16.
29    const N: usize;
30    /// Register type.
31    ///
32    /// `u32` for RV32 and `u64` for RV64.
33    type Type: [const] Default
34        + [const] From<u8>
35        + [const] Into<u64>
36        + [const] Eq
37        + [const] Add
38        + [const] AddAssign
39        + [const] Sub
40        + [const] SubAssign
41        + fmt::Display
42        + fmt::Debug
43        + Copy
44        + Sized;
45
46    /// Whether the register is a zero register
47    fn is_zero(&self) -> bool;
48
49    /// Create a register from its bit representation
50    fn from_bits(bits: u8) -> Option<Self>;
51
52    /// Offset in a set of registers
53    fn offset(self) -> usize;
54}
55
56/// A set of RISC-V general purpose registers
57#[derive(Debug, Clone, Copy)]
58pub struct Registers<Reg>
59where
60    Reg: Register,
61    [(); Reg::N]:,
62{
63    regs: [Reg::Type; Reg::N],
64}
65
66impl<Reg> Default for Registers<Reg>
67where
68    Reg: Register,
69    [(); Reg::N]: Default,
70{
71    #[inline(always)]
72    fn default() -> Self {
73        Self {
74            regs: [Reg::Type::default(); Reg::N],
75        }
76    }
77}
78
79const impl<Reg> Registers<Reg>
80where
81    Reg: Register + [const] Eq,
82    [(); Reg::N]:,
83{
84    #[inline(always)]
85    pub fn read(&self, reg: Reg) -> Reg::Type
86    where
87        Reg: [const] Register,
88    {
89        if reg.is_zero() {
90            // Always zero
91            return Reg::Type::default();
92        }
93
94        // SAFETY: register offset is always within bounds
95        *unsafe { self.regs.get_unchecked(reg.offset()) }
96    }
97
98    #[inline(always)]
99    pub fn write(&mut self, reg: Reg, value: Reg::Type)
100    where
101        Reg: [const] Register,
102    {
103        if reg.is_zero() {
104            // Writes are ignored
105            return;
106        }
107
108        // SAFETY: register offset is always within bounds
109        *unsafe { self.regs.get_unchecked_mut(reg.offset()) } = value;
110    }
111}
112
113/// RISC-V general purpose register for RV32E/RV64E.
114///
115/// Use `Type = u32` for RV32E and `Type = u64` for RV64E.
116#[derive(Clone, Copy)]
117#[repr(u8)]
118pub enum EReg<Type> {
119    /// Always zero: `x0`
120    Zero = 0,
121    /// Return address: `x1`
122    Ra = 1,
123    /// Stack pointer: `x2`
124    Sp = 2,
125    /// Global pointer: `x3`
126    Gp = 3,
127    /// Thread pointer: `x4`
128    Tp = 4,
129    /// Temporary/alternate return address: `x5`
130    T0 = 5,
131    /// Temporary: `x6`
132    T1 = 6,
133    /// Temporary: `x7`
134    T2 = 7,
135    /// Saved register/frame pointer: `x8`
136    S0 = 8,
137    /// Saved register: `x9`
138    S1 = 9,
139    /// Function argument/return value: `x10`
140    A0 = 10,
141    /// Function argument/return value: `x11`
142    A1 = 11,
143    /// Function argument: `x12`
144    A2 = 12,
145    /// Function argument: `x13`
146    A3 = 13,
147    /// Function argument: `x14`
148    A4 = 14,
149    /// Function argument: `x15`
150    A5 = 15,
151    /// Phantom register that is never constructed and is only used due to type system limitations
152    #[doc(hidden)]
153    Phantom(PhantomRegister<Type>),
154}
155
156impl<Type> fmt::Display for EReg<Type> {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        match self {
159            Self::Zero => write!(f, "zero"),
160            Self::Ra => write!(f, "ra"),
161            Self::Sp => write!(f, "sp"),
162            Self::Gp => write!(f, "gp"),
163            Self::Tp => write!(f, "tp"),
164            Self::T0 => write!(f, "t0"),
165            Self::T1 => write!(f, "t1"),
166            Self::T2 => write!(f, "t2"),
167            Self::S0 => write!(f, "s0"),
168            Self::S1 => write!(f, "s1"),
169            Self::A0 => write!(f, "a0"),
170            Self::A1 => write!(f, "a1"),
171            Self::A2 => write!(f, "a2"),
172            Self::A3 => write!(f, "a3"),
173            Self::A4 => write!(f, "a4"),
174            Self::A5 => write!(f, "a5"),
175            Self::Phantom(_) => {
176                // SAFETY: Phantom register is never constructed
177                unsafe { unreachable_unchecked() }
178            }
179        }
180    }
181}
182
183impl<Type> fmt::Debug for EReg<Type> {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        fmt::Display::fmt(self, f)
186    }
187}
188
189impl<Type> const PartialEq for EReg<Type> {
190    #[inline(always)]
191    fn eq(&self, other: &Self) -> bool {
192        // This is quite ugly, but there doesn't seem to be a much better way with `Phantom` variant
193        matches!(
194            (self, other),
195            (Self::Zero, Self::Zero)
196                | (Self::Ra, Self::Ra)
197                | (Self::Sp, Self::Sp)
198                | (Self::Gp, Self::Gp)
199                | (Self::Tp, Self::Tp)
200                | (Self::T0, Self::T0)
201                | (Self::T1, Self::T1)
202                | (Self::T2, Self::T2)
203                | (Self::S0, Self::S0)
204                | (Self::S1, Self::S1)
205                | (Self::A0, Self::A0)
206                | (Self::A1, Self::A1)
207                | (Self::A2, Self::A2)
208                | (Self::A3, Self::A3)
209                | (Self::A4, Self::A4)
210                | (Self::A5, Self::A5)
211                | (Self::Phantom(_), Self::Phantom(_))
212        )
213    }
214}
215
216impl<Type> const Eq for EReg<Type> {}
217
218// SAFETY: `Self::offset()` returns values within `0..Self::N` range
219unsafe impl const Register for EReg<u32> {
220    const N: usize = 16;
221    type Type = u32;
222
223    #[inline(always)]
224    fn is_zero(&self) -> bool {
225        matches!(self, Self::Zero)
226    }
227
228    #[inline(always)]
229    fn from_bits(bits: u8) -> Option<Self> {
230        match bits {
231            0 => Some(Self::Zero),
232            1 => Some(Self::Ra),
233            2 => Some(Self::Sp),
234            3 => Some(Self::Gp),
235            4 => Some(Self::Tp),
236            5 => Some(Self::T0),
237            6 => Some(Self::T1),
238            7 => Some(Self::T2),
239            8 => Some(Self::S0),
240            9 => Some(Self::S1),
241            10 => Some(Self::A0),
242            11 => Some(Self::A1),
243            12 => Some(Self::A2),
244            13 => Some(Self::A3),
245            14 => Some(Self::A4),
246            15 => Some(Self::A5),
247            _ => None,
248        }
249    }
250
251    #[inline(always)]
252    fn offset(self) -> usize {
253        // NOTE: `transmute()` is requited here, otherwise performance suffers A LOT for unknown
254        // reason
255        // SAFETY: Enum is `#[repr(u8)]` and doesn't have any fields
256        usize::from(unsafe { core::mem::transmute::<Self, u8>(self) })
257        // match self {
258        //     Self::Zero => 0,
259        //     Self::Ra => 1,
260        //     Self::Sp => 2,
261        //     Self::Gp => 3,
262        //     Self::Tp => 4,
263        //     Self::T0 => 5,
264        //     Self::T1 => 6,
265        //     Self::T2 => 7,
266        //     Self::S0 => 8,
267        //     Self::S1 => 9,
268        //     Self::A0 => 10,
269        //     Self::A1 => 11,
270        //     Self::A2 => 12,
271        //     Self::A3 => 13,
272        //     Self::A4 => 14,
273        //     Self::A5 => 15,
274        //     Self::Phantom(_) => {
275        //         // SAFETY: Phantom register is never constructed
276        //         unsafe { unreachable_unchecked() }
277        //     },
278        // }
279    }
280}
281
282// SAFETY: `Self::offset()` returns values within `0..Self::N` range
283unsafe impl const Register for EReg<u64> {
284    const N: usize = 16;
285    type Type = u64;
286
287    #[inline(always)]
288    fn is_zero(&self) -> bool {
289        matches!(self, Self::Zero)
290    }
291
292    #[inline(always)]
293    fn from_bits(bits: u8) -> Option<Self> {
294        match bits {
295            0 => Some(Self::Zero),
296            1 => Some(Self::Ra),
297            2 => Some(Self::Sp),
298            3 => Some(Self::Gp),
299            4 => Some(Self::Tp),
300            5 => Some(Self::T0),
301            6 => Some(Self::T1),
302            7 => Some(Self::T2),
303            8 => Some(Self::S0),
304            9 => Some(Self::S1),
305            10 => Some(Self::A0),
306            11 => Some(Self::A1),
307            12 => Some(Self::A2),
308            13 => Some(Self::A3),
309            14 => Some(Self::A4),
310            15 => Some(Self::A5),
311            _ => None,
312        }
313    }
314
315    #[inline(always)]
316    fn offset(self) -> usize {
317        // NOTE: `transmute()` is requited here, otherwise performance suffers A LOT for unknown
318        // reason
319        // SAFETY: Enum is `#[repr(u8)]` and doesn't have any fields
320        usize::from(unsafe { core::mem::transmute::<Self, u8>(self) })
321        // match self {
322        //     Self::Zero => 0,
323        //     Self::Ra => 1,
324        //     Self::Sp => 2,
325        //     Self::Gp => 3,
326        //     Self::Tp => 4,
327        //     Self::T0 => 5,
328        //     Self::T1 => 6,
329        //     Self::T2 => 7,
330        //     Self::S0 => 8,
331        //     Self::S1 => 9,
332        //     Self::A0 => 10,
333        //     Self::A1 => 11,
334        //     Self::A2 => 12,
335        //     Self::A3 => 13,
336        //     Self::A4 => 14,
337        //     Self::A5 => 15,
338        //     Self::Phantom(_) => {
339        //         // SAFETY: Phantom register is never constructed
340        //         unsafe { unreachable_unchecked() }
341        //     },
342        // }
343    }
344}
345
346/// RISC-V general purpose register for RV32I/RV64I.
347///
348/// Use `Type = u32` for RV32I and `Type = u64` for RV64I.
349#[derive(Clone, Copy)]
350#[repr(u8)]
351pub enum Reg<Type> {
352    /// Always zero: `x0`
353    Zero = 0,
354    /// Return address: `x1`
355    Ra = 1,
356    /// Stack pointer: `x2`
357    Sp = 2,
358    /// Global pointer: `x3`
359    Gp = 3,
360    /// Thread pointer: `x4`
361    Tp = 4,
362    /// Temporary/alternate return address: `x5`
363    T0 = 5,
364    /// Temporary: `x6`
365    T1 = 6,
366    /// Temporary: `x7`
367    T2 = 7,
368    /// Saved register/frame pointer: `x8`
369    S0 = 8,
370    /// Saved register: `x9`
371    S1 = 9,
372    /// Function argument/return value: `x10`
373    A0 = 10,
374    /// Function argument/return value: `x11`
375    A1 = 11,
376    /// Function argument: `x12`
377    A2 = 12,
378    /// Function argument: `x13`
379    A3 = 13,
380    /// Function argument: `x14`
381    A4 = 14,
382    /// Function argument: `x15`
383    A5 = 15,
384    /// Function argument: `x16`
385    A6 = 16,
386    /// Function argument: `x17`
387    A7 = 17,
388    /// Saved register: `x18`
389    S2 = 18,
390    /// Saved register: `x19`
391    S3 = 19,
392    /// Saved register: `x20`
393    S4 = 20,
394    /// Saved register: `x21`
395    S5 = 21,
396    /// Saved register: `x22`
397    S6 = 22,
398    /// Saved register: `x23`
399    S7 = 23,
400    /// Saved register: `x24`
401    S8 = 24,
402    /// Saved register: `x25`
403    S9 = 25,
404    /// Saved register: `x26`
405    S10 = 26,
406    /// Saved register: `x27`
407    S11 = 27,
408    /// Temporary: `x28`
409    T3 = 28,
410    /// Temporary: `x29`
411    T4 = 29,
412    /// Temporary: `x30`
413    T5 = 30,
414    /// Temporary: `x31`
415    T6 = 31,
416    /// Phantom register that is never constructed and is only used due to type system limitations
417    #[doc(hidden)]
418    Phantom(PhantomRegister<Type>),
419}
420
421impl<Type> const From<EReg<u64>> for Reg<Type> {
422    #[inline(always)]
423    fn from(reg: EReg<u64>) -> Self {
424        match reg {
425            EReg::Zero => Self::Zero,
426            EReg::Ra => Self::Ra,
427            EReg::Sp => Self::Sp,
428            EReg::Gp => Self::Gp,
429            EReg::Tp => Self::Tp,
430            EReg::T0 => Self::T0,
431            EReg::T1 => Self::T1,
432            EReg::T2 => Self::T2,
433            EReg::S0 => Self::S0,
434            EReg::S1 => Self::S1,
435            EReg::A0 => Self::A0,
436            EReg::A1 => Self::A1,
437            EReg::A2 => Self::A2,
438            EReg::A3 => Self::A3,
439            EReg::A4 => Self::A4,
440            EReg::A5 => Self::A5,
441            EReg::Phantom(_) => {
442                // SAFETY: Phantom register is never constructed
443                unsafe { unreachable_unchecked() }
444            }
445        }
446    }
447}
448
449impl<Type> fmt::Display for Reg<Type> {
450    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451        match self {
452            Self::Zero => write!(f, "zero"),
453            Self::Ra => write!(f, "ra"),
454            Self::Sp => write!(f, "sp"),
455            Self::Gp => write!(f, "gp"),
456            Self::Tp => write!(f, "tp"),
457            Self::T0 => write!(f, "t0"),
458            Self::T1 => write!(f, "t1"),
459            Self::T2 => write!(f, "t2"),
460            Self::S0 => write!(f, "s0"),
461            Self::S1 => write!(f, "s1"),
462            Self::A0 => write!(f, "a0"),
463            Self::A1 => write!(f, "a1"),
464            Self::A2 => write!(f, "a2"),
465            Self::A3 => write!(f, "a3"),
466            Self::A4 => write!(f, "a4"),
467            Self::A5 => write!(f, "a5"),
468            Self::A6 => write!(f, "a6"),
469            Self::A7 => write!(f, "a7"),
470            Self::S2 => write!(f, "s2"),
471            Self::S3 => write!(f, "s3"),
472            Self::S4 => write!(f, "s4"),
473            Self::S5 => write!(f, "s5"),
474            Self::S6 => write!(f, "s6"),
475            Self::S7 => write!(f, "s7"),
476            Self::S8 => write!(f, "s8"),
477            Self::S9 => write!(f, "s9"),
478            Self::S10 => write!(f, "s10"),
479            Self::S11 => write!(f, "s11"),
480            Self::T3 => write!(f, "t3"),
481            Self::T4 => write!(f, "t4"),
482            Self::T5 => write!(f, "t5"),
483            Self::T6 => write!(f, "t6"),
484            Self::Phantom(_) => {
485                // SAFETY: Phantom register is never constructed
486                unsafe { unreachable_unchecked() }
487            }
488        }
489    }
490}
491
492impl<Type> fmt::Debug for Reg<Type> {
493    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494        fmt::Display::fmt(self, f)
495    }
496}
497
498impl<Type> const PartialEq for Reg<Type> {
499    #[inline(always)]
500    fn eq(&self, other: &Self) -> bool {
501        // This is quite ugly, but there doesn't seem to be a much better way with `Phantom` variant
502        matches!(
503            (self, other),
504            (Self::Zero, Self::Zero)
505                | (Self::Ra, Self::Ra)
506                | (Self::Sp, Self::Sp)
507                | (Self::Gp, Self::Gp)
508                | (Self::Tp, Self::Tp)
509                | (Self::T0, Self::T0)
510                | (Self::T1, Self::T1)
511                | (Self::T2, Self::T2)
512                | (Self::S0, Self::S0)
513                | (Self::S1, Self::S1)
514                | (Self::A0, Self::A0)
515                | (Self::A1, Self::A1)
516                | (Self::A2, Self::A2)
517                | (Self::A3, Self::A3)
518                | (Self::A4, Self::A4)
519                | (Self::A5, Self::A5)
520                | (Self::A6, Self::A6)
521                | (Self::A7, Self::A7)
522                | (Self::S2, Self::S2)
523                | (Self::S3, Self::S3)
524                | (Self::S4, Self::S4)
525                | (Self::S5, Self::S5)
526                | (Self::S6, Self::S6)
527                | (Self::S7, Self::S7)
528                | (Self::S8, Self::S8)
529                | (Self::S9, Self::S9)
530                | (Self::S10, Self::S10)
531                | (Self::S11, Self::S11)
532                | (Self::T3, Self::T3)
533                | (Self::T4, Self::T4)
534                | (Self::T5, Self::T5)
535                | (Self::T6, Self::T6)
536                | (Self::Phantom(_), Self::Phantom(_))
537        )
538    }
539}
540
541impl<Type> const Eq for Reg<Type> {}
542
543// SAFETY: `Self::offset()` returns values within `0..Self::N` range
544unsafe impl const Register for Reg<u32> {
545    const N: usize = 32;
546    type Type = u32;
547
548    #[inline(always)]
549    fn is_zero(&self) -> bool {
550        matches!(self, Self::Zero)
551    }
552
553    #[inline(always)]
554    fn from_bits(bits: u8) -> Option<Self> {
555        match bits {
556            0 => Some(Self::Zero),
557            1 => Some(Self::Ra),
558            2 => Some(Self::Sp),
559            3 => Some(Self::Gp),
560            4 => Some(Self::Tp),
561            5 => Some(Self::T0),
562            6 => Some(Self::T1),
563            7 => Some(Self::T2),
564            8 => Some(Self::S0),
565            9 => Some(Self::S1),
566            10 => Some(Self::A0),
567            11 => Some(Self::A1),
568            12 => Some(Self::A2),
569            13 => Some(Self::A3),
570            14 => Some(Self::A4),
571            15 => Some(Self::A5),
572            16 => Some(Self::A6),
573            17 => Some(Self::A7),
574            18 => Some(Self::S2),
575            19 => Some(Self::S3),
576            20 => Some(Self::S4),
577            21 => Some(Self::S5),
578            22 => Some(Self::S6),
579            23 => Some(Self::S7),
580            24 => Some(Self::S8),
581            25 => Some(Self::S9),
582            26 => Some(Self::S10),
583            27 => Some(Self::S11),
584            28 => Some(Self::T3),
585            29 => Some(Self::T4),
586            30 => Some(Self::T5),
587            31 => Some(Self::T6),
588            _ => None,
589        }
590    }
591
592    #[inline(always)]
593    fn offset(self) -> usize {
594        // NOTE: `transmute()` is requited here, otherwise performance suffers A LOT for unknown
595        // reason
596        // SAFETY: Enum is `#[repr(u8)]` and doesn't have any fields
597        usize::from(unsafe { core::mem::transmute::<Self, u8>(self) })
598        // match self {
599        //     Self::Zero => 0,
600        //     Self::Ra => 1,
601        //     Self::Sp => 2,
602        //     Self::Gp => 3,
603        //     Self::Tp => 4,
604        //     Self::T0 => 5,
605        //     Self::T1 => 6,
606        //     Self::T2 => 7,
607        //     Self::S0 => 8,
608        //     Self::S1 => 9,
609        //     Self::A0 => 10,
610        //     Self::A1 => 11,
611        //     Self::A2 => 12,
612        //     Self::A3 => 13,
613        //     Self::A4 => 14,
614        //     Self::A5 => 15,
615        //     Self::A6 => 16,
616        //     Self::A7 => 17,
617        //     Self::S2 => 18,
618        //     Self::S3 => 19,
619        //     Self::S4 => 20,
620        //     Self::S5 => 21,
621        //     Self::S6 => 22,
622        //     Self::S7 => 23,
623        //     Self::S8 => 24,
624        //     Self::S9 => 25,
625        //     Self::S10 => 26,
626        //     Self::S11 => 27,
627        //     Self::T3 => 28,
628        //     Self::T4 => 29,
629        //     Self::T5 => 30,
630        //     Self::T6 => 31,
631        //     Self::Phantom(_) => {
632        //         // SAFETY: Phantom register is never constructed
633        //         unsafe { unreachable_unchecked() }
634        //     }
635        // }
636    }
637}
638
639// SAFETY: `Self::offset()` returns values within `0..Self::N` range
640unsafe impl const Register for Reg<u64> {
641    const N: usize = 32;
642    type Type = u64;
643
644    #[inline(always)]
645    fn is_zero(&self) -> bool {
646        matches!(self, Self::Zero)
647    }
648
649    #[inline(always)]
650    fn from_bits(bits: u8) -> Option<Self> {
651        match bits {
652            0 => Some(Self::Zero),
653            1 => Some(Self::Ra),
654            2 => Some(Self::Sp),
655            3 => Some(Self::Gp),
656            4 => Some(Self::Tp),
657            5 => Some(Self::T0),
658            6 => Some(Self::T1),
659            7 => Some(Self::T2),
660            8 => Some(Self::S0),
661            9 => Some(Self::S1),
662            10 => Some(Self::A0),
663            11 => Some(Self::A1),
664            12 => Some(Self::A2),
665            13 => Some(Self::A3),
666            14 => Some(Self::A4),
667            15 => Some(Self::A5),
668            16 => Some(Self::A6),
669            17 => Some(Self::A7),
670            18 => Some(Self::S2),
671            19 => Some(Self::S3),
672            20 => Some(Self::S4),
673            21 => Some(Self::S5),
674            22 => Some(Self::S6),
675            23 => Some(Self::S7),
676            24 => Some(Self::S8),
677            25 => Some(Self::S9),
678            26 => Some(Self::S10),
679            27 => Some(Self::S11),
680            28 => Some(Self::T3),
681            29 => Some(Self::T4),
682            30 => Some(Self::T5),
683            31 => Some(Self::T6),
684            _ => None,
685        }
686    }
687
688    #[inline(always)]
689    fn offset(self) -> usize {
690        // NOTE: `transmute()` is requited here, otherwise performance suffers A LOT for unknown
691        // reason
692        // SAFETY: Enum is `#[repr(u8)]` and doesn't have any fields
693        usize::from(unsafe { core::mem::transmute::<Self, u8>(self) })
694        // match self {
695        //     Self::Zero => 0,
696        //     Self::Ra => 1,
697        //     Self::Sp => 2,
698        //     Self::Gp => 3,
699        //     Self::Tp => 4,
700        //     Self::T0 => 5,
701        //     Self::T1 => 6,
702        //     Self::T2 => 7,
703        //     Self::S0 => 8,
704        //     Self::S1 => 9,
705        //     Self::A0 => 10,
706        //     Self::A1 => 11,
707        //     Self::A2 => 12,
708        //     Self::A3 => 13,
709        //     Self::A4 => 14,
710        //     Self::A5 => 15,
711        //     Self::A6 => 16,
712        //     Self::A7 => 17,
713        //     Self::S2 => 18,
714        //     Self::S3 => 19,
715        //     Self::S4 => 20,
716        //     Self::S5 => 21,
717        //     Self::S6 => 22,
718        //     Self::S7 => 23,
719        //     Self::S8 => 24,
720        //     Self::S9 => 25,
721        //     Self::S10 => 26,
722        //     Self::S11 => 27,
723        //     Self::T3 => 28,
724        //     Self::T4 => 29,
725        //     Self::T5 => 30,
726        //     Self::T6 => 31,
727        //     Self::Phantom(_) => {
728        //         // SAFETY: Phantom register is never constructed
729        //         unsafe { unreachable_unchecked() }
730        //     }
731        // }
732    }
733}