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}