cranelift_codegen/machinst/
valueregs.rs

1//! Data structure for tracking the (possibly multiple) registers that hold one
2//! SSA `Value`.
3
4use regalloc2::{PReg, VReg};
5
6use super::{RealReg, Reg, VirtualReg, Writable};
7use std::fmt::Debug;
8
9const VALUE_REGS_PARTS: usize = 2;
10
11/// Location at which a `Value` is stored in register(s): the value is located
12/// in one or more registers, depending on its width. A value may be stored in
13/// more than one register if the machine has no registers wide enough
14/// otherwise: for example, on a 32-bit architecture, we may store `I64` values
15/// in two registers, and `I128` values in four.
16///
17/// By convention, the register parts are kept in machine-endian order here.
18///
19/// N.B.: we cap the capacity of this at four (when any 32-bit target is
20/// enabled) or two (otherwise), and we use special in-band sentinel `Reg`
21/// values (`Reg::invalid()`) to avoid the need to carry a separate length. This
22/// allows the struct to be `Copy` (no heap or drop overhead) and be only 16 or
23/// 8 bytes, which is important for compiler performance.
24#[derive(Clone, Copy, PartialEq, Eq)]
25pub struct ValueRegs<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> {
26    parts: [R; VALUE_REGS_PARTS],
27}
28
29impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> Debug for ValueRegs<R> {
30    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31        let mut f = f.debug_tuple("ValueRegs");
32        let mut last_valid = true;
33        for part in self.parts {
34            if part.is_invalid_sentinel() {
35                last_valid = false;
36            } else {
37                debug_assert!(last_valid);
38                f.field(&part);
39            }
40        }
41        f.finish()
42    }
43}
44
45/// A type with an "invalid" sentinel value.
46pub trait InvalidSentinel: Copy + Eq {
47    /// The invalid sentinel value.
48    fn invalid_sentinel() -> Self;
49    /// Is this the invalid sentinel?
50    fn is_invalid_sentinel(self) -> bool {
51        self == Self::invalid_sentinel()
52    }
53}
54impl InvalidSentinel for Reg {
55    fn invalid_sentinel() -> Self {
56        Reg::from(VReg::invalid())
57    }
58}
59impl InvalidSentinel for VirtualReg {
60    fn invalid_sentinel() -> Self {
61        VirtualReg::from(VReg::invalid())
62    }
63}
64impl InvalidSentinel for RealReg {
65    fn invalid_sentinel() -> Self {
66        RealReg::from(PReg::invalid())
67    }
68}
69impl InvalidSentinel for Writable<Reg> {
70    fn invalid_sentinel() -> Self {
71        Writable::from_reg(Reg::invalid_sentinel())
72    }
73}
74
75impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
76    /// Create an invalid Value-in-Reg.
77    pub fn invalid() -> Self {
78        ValueRegs {
79            parts: [R::invalid_sentinel(); VALUE_REGS_PARTS],
80        }
81    }
82
83    /// Is this Value-to-Reg mapping valid?
84    pub fn is_valid(self) -> bool {
85        !self.parts[0].is_invalid_sentinel()
86    }
87    /// Is this Value-to-Reg mapping invalid?
88    pub fn is_invalid(self) -> bool {
89        self.parts[0].is_invalid_sentinel()
90    }
91
92    /// Return the single register used for this value, if any.
93    pub fn only_reg(self) -> Option<R> {
94        if self.len() == 1 {
95            Some(self.parts[0])
96        } else {
97            None
98        }
99    }
100
101    /// Return a slice of the registers storing this value.
102    pub fn regs(&self) -> &[R] {
103        &self.parts[0..self.len()]
104    }
105
106    /// Return a mutable slice of the registers storing this value.
107    pub fn regs_mut(&mut self) -> &mut [R] {
108        let len = self.len();
109        &mut self.parts[0..len]
110    }
111}
112
113impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
114    /// Create a Value-in-R location for a value stored in one register.
115    pub fn one(reg: R) -> Self {
116        ValueRegs {
117            parts: [reg, R::invalid_sentinel()],
118        }
119    }
120    /// Create a Value-in-R location for a value stored in two registers.
121    pub fn two(r1: R, r2: R) -> Self {
122        ValueRegs { parts: [r1, r2] }
123    }
124
125    /// Return the number of registers used.
126    pub fn len(self) -> usize {
127        // If rustc/LLVM is smart enough, this might even be vectorized...
128        (self.parts[0] != R::invalid_sentinel()) as usize
129            + (self.parts[1] != R::invalid_sentinel()) as usize
130    }
131
132    /// Map individual registers via a map function.
133    pub fn map<NewR, F>(self, f: F) -> ValueRegs<NewR>
134    where
135        NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel,
136        F: Fn(R) -> NewR,
137    {
138        ValueRegs {
139            parts: [f(self.parts[0]), f(self.parts[1])],
140        }
141    }
142}
143
144/// Create a writable ValueRegs.
145#[allow(dead_code)]
146pub(crate) fn writable_value_regs(regs: ValueRegs<Reg>) -> ValueRegs<Writable<Reg>> {
147    regs.map(|r| Writable::from_reg(r))
148}
149
150/// Strip a writable ValueRegs down to a readonly ValueRegs.
151#[allow(dead_code)]
152pub(crate) fn non_writable_value_regs(regs: ValueRegs<Writable<Reg>>) -> ValueRegs<Reg> {
153    regs.map(|r| r.to_reg())
154}