1 //! Data structure for tracking the (possibly multiple) registers that hold one
2 //! SSA `Value`.
3 
4 use regalloc2::{PReg, VReg};
5 
6 use super::{RealReg, Reg, VirtualReg, Writable};
7 use std::fmt::Debug;
8 
9 const 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 sentinal `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, Debug, PartialEq, Eq)]
25 pub struct ValueRegs<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> {
26     parts: [R; VALUE_REGS_PARTS],
27 }
28 
29 /// A type with an "invalid" sentinel value.
30 pub trait InvalidSentinel: Copy + Eq {
31     /// The invalid sentinel value.
32     fn invalid_sentinel() -> Self;
33     /// Is this the invalid sentinel?
34     fn is_invalid_sentinel(self) -> bool {
35         self == Self::invalid_sentinel()
36     }
37 }
38 impl InvalidSentinel for Reg {
39     fn invalid_sentinel() -> Self {
40         Reg::from(VReg::invalid())
41     }
42 }
43 impl InvalidSentinel for VirtualReg {
44     fn invalid_sentinel() -> Self {
45         VirtualReg::from(VReg::invalid())
46     }
47 }
48 impl InvalidSentinel for RealReg {
49     fn invalid_sentinel() -> Self {
50         RealReg::from(PReg::invalid())
51     }
52 }
53 impl InvalidSentinel for Writable<Reg> {
54     fn invalid_sentinel() -> Self {
55         Writable::from_reg(Reg::invalid_sentinel())
56     }
57 }
58 
59 impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
60     /// Create an invalid Value-in-Reg.
61     pub fn invalid() -> Self {
62         ValueRegs {
63             parts: [R::invalid_sentinel(); VALUE_REGS_PARTS],
64         }
65     }
66 
67     /// Is this Value-to-Reg mapping valid?
68     pub fn is_valid(self) -> bool {
69         !self.parts[0].is_invalid_sentinel()
70     }
71     /// Is this Value-to-Reg mapping invalid?
72     pub fn is_invalid(self) -> bool {
73         self.parts[0].is_invalid_sentinel()
74     }
75 
76     /// Return the single register used for this value, if any.
77     pub fn only_reg(self) -> Option<R> {
78         if self.len() == 1 {
79             Some(self.parts[0])
80         } else {
81             None
82         }
83     }
84 
85     /// Return a slice of the registers storing this value.
86     pub fn regs(&self) -> &[R] {
87         &self.parts[0..self.len()]
88     }
89 
90     /// Return a mutable slice of the registers storing this value.
91     pub fn regs_mut(&mut self) -> &mut [R] {
92         let len = self.len();
93         &mut self.parts[0..len]
94     }
95 }
96 
97 impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
98     /// Create a Value-in-R location for a value stored in one register.
99     pub fn one(reg: R) -> Self {
100         ValueRegs {
101             parts: [reg, R::invalid_sentinel()],
102         }
103     }
104     /// Create a Value-in-R location for a value stored in two registers.
105     pub fn two(r1: R, r2: R) -> Self {
106         ValueRegs { parts: [r1, r2] }
107     }
108 
109     /// Return the number of registers used.
110     pub fn len(self) -> usize {
111         // If rustc/LLVM is smart enough, this might even be vectorized...
112         (self.parts[0] != R::invalid_sentinel()) as usize
113             + (self.parts[1] != R::invalid_sentinel()) as usize
114     }
115 
116     /// Map individual registers via a map function.
117     pub fn map<NewR, F>(self, f: F) -> ValueRegs<NewR>
118     where
119         NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel,
120         F: Fn(R) -> NewR,
121     {
122         ValueRegs {
123             parts: [f(self.parts[0]), f(self.parts[1])],
124         }
125     }
126 }
127 
128 /// Create a writable ValueRegs.
129 #[allow(dead_code)]
130 pub(crate) fn writable_value_regs(regs: ValueRegs<Reg>) -> ValueRegs<Writable<Reg>> {
131     regs.map(|r| Writable::from_reg(r))
132 }
133 
134 /// Strip a writable ValueRegs down to a readonly ValueRegs.
135 #[allow(dead_code)]
136 pub(crate) fn non_writable_value_regs(regs: ValueRegs<Writable<Reg>>) -> ValueRegs<Reg> {
137     regs.map(|r| r.to_reg())
138 }
139