cranelift_assembler_x64/
fixed.rs

1//! Operands with fixed register encodings.
2
3use 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)]
26pub struct Fixed<R, const E: u8>(pub R);
27
28impl<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: Size) -> String
39    where
40        R: AsReg,
41    {
42        self.0.to_string(Some(size))
43    }
44}
45
46impl<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
58impl<R, const E: u8> AsRef<R> for Fixed<R, E> {
59    fn as_ref(&self) -> &R {
60        &self.0
61    }
62}
63
64impl<R, const E: u8> From<R> for Fixed<R, E> {
65    fn from(reg: R) -> Fixed<R, E> {
66        Fixed(reg)
67    }
68}