cranelift_assembler_x64/
fixed.rs

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