1 //! Operands with fixed register encodings.
2 
3 use crate::{AsReg, Size};
4 
5 /// A _fixed_ register.
6 ///
7 /// Some operands are implicit to the instruction and thus use a fixed register
8 /// for execution. Because this assembler is generic over any register type
9 /// (`R`), this wrapper provides a way to record the fixed register encoding we
10 /// expect to use (`E`).
11 ///
12 /// ```
13 /// # use cranelift_assembler_x64::{AsReg, Fixed, gpr};
14 /// # let valid_reg = 0;
15 /// let fixed = Fixed::<u8, { gpr::enc::RAX }>(valid_reg);
16 /// assert_eq!(fixed.enc(), gpr::enc::RAX);
17 /// ```
18 ///
19 /// ```should_panic
20 /// # use cranelift_assembler_x64::{AsReg, Fixed, gpr};
21 /// # let invalid_reg = 42;
22 /// let fixed = Fixed::<u8, { gpr::enc::RAX }>(invalid_reg);
23 /// fixed.enc(); // Will panic because `invalid_reg` does not match `RAX`.
24 /// ```
25 #[derive(Copy, Clone, Debug, PartialEq)]
26 pub struct Fixed<R, const E: u8>(pub R);
27 
28 impl<R, const E: u8> Fixed<R, E> {
29     /// Return the fixed register encoding.
30     ///
31     /// Regardless of what `R` is (e.g., pre-register allocation), we want to be
32     /// able to know what this register should encode as.
33     pub fn expected_enc(&self) -> u8 {
34         E
35     }
36 
37     /// Return the register name at the given `size`.
38     pub fn to_string(&self, size: Option<Size>) -> String
39     where
40         R: AsReg,
41     {
42         self.0.to_string(size)
43     }
44 }
45 
46 impl<R: AsReg, const E: u8> AsReg for Fixed<R, E> {
47     fn new(reg: u8) -> Self {
48         assert!(reg == E);
49         Self(R::new(reg))
50     }
51 
52     fn enc(&self) -> u8 {
53         assert!(self.0.enc() == E);
54         self.0.enc()
55     }
56 }
57 
58 impl<R, const E: u8> AsRef<R> for Fixed<R, E> {
59     fn as_ref(&self) -> &R {
60         &self.0
61     }
62 }
63 
64 impl<R, const E: u8> From<R> for Fixed<R, E> {
65     fn from(reg: R) -> Fixed<R, E> {
66         Fixed(reg)
67     }
68 }
69