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