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 core::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 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)] 25 pub struct ValueRegs<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> { 26 parts: [R; VALUE_REGS_PARTS], 27 } 28 29 impl<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. 46 pub 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 } 54 impl InvalidSentinel for Reg { 55 fn invalid_sentinel() -> Self { 56 Reg::from(VReg::invalid()) 57 } 58 } 59 impl InvalidSentinel for VirtualReg { 60 fn invalid_sentinel() -> Self { 61 VirtualReg::from(VReg::invalid()) 62 } 63 } 64 impl InvalidSentinel for RealReg { 65 fn invalid_sentinel() -> Self { 66 RealReg::from(PReg::invalid()) 67 } 68 } 69 impl InvalidSentinel for Writable<Reg> { 70 fn invalid_sentinel() -> Self { 71 Writable::from_reg(Reg::invalid_sentinel()) 72 } 73 } 74 75 impl<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 113 impl<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 pub(crate) fn writable_value_regs(regs: ValueRegs<Reg>) -> ValueRegs<Writable<Reg>> { 146 regs.map(|r| Writable::from_reg(r)) 147 } 148 149 /// Strip a writable ValueRegs down to a readonly ValueRegs. 150 pub(crate) fn non_writable_value_regs(regs: ValueRegs<Writable<Reg>>) -> ValueRegs<Reg> { 151 regs.map(|r| r.to_reg()) 152 } 153