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