Path: blob/main/cranelift/codegen/src/machinst/valueregs.rs
1693 views
//! Data structure for tracking the (possibly multiple) registers that hold one1//! SSA `Value`.23use regalloc2::{PReg, VReg};45use super::{RealReg, Reg, VirtualReg, Writable};6use std::fmt::Debug;78const VALUE_REGS_PARTS: usize = 2;910/// Location at which a `Value` is stored in register(s): the value is located11/// in one or more registers, depending on its width. A value may be stored in12/// more than one register if the machine has no registers wide enough13/// otherwise: for example, on a 32-bit architecture, we may store `I64` values14/// in two registers, and `I128` values in four.15///16/// By convention, the register parts are kept in machine-endian order here.17///18/// N.B.: we cap the capacity of this at four (when any 32-bit target is19/// enabled) or two (otherwise), and we use special in-band sentinel `Reg`20/// values (`Reg::invalid()`) to avoid the need to carry a separate length. This21/// allows the struct to be `Copy` (no heap or drop overhead) and be only 16 or22/// 8 bytes, which is important for compiler performance.23#[derive(Clone, Copy, PartialEq, Eq)]24pub struct ValueRegs<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> {25parts: [R; VALUE_REGS_PARTS],26}2728impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> Debug for ValueRegs<R> {29fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {30let mut f = f.debug_tuple("ValueRegs");31let mut last_valid = true;32for part in self.parts {33if part.is_invalid_sentinel() {34last_valid = false;35} else {36debug_assert!(last_valid);37f.field(&part);38}39}40f.finish()41}42}4344/// A type with an "invalid" sentinel value.45pub trait InvalidSentinel: Copy + Eq {46/// The invalid sentinel value.47fn invalid_sentinel() -> Self;48/// Is this the invalid sentinel?49fn is_invalid_sentinel(self) -> bool {50self == Self::invalid_sentinel()51}52}53impl InvalidSentinel for Reg {54fn invalid_sentinel() -> Self {55Reg::from(VReg::invalid())56}57}58impl InvalidSentinel for VirtualReg {59fn invalid_sentinel() -> Self {60VirtualReg::from(VReg::invalid())61}62}63impl InvalidSentinel for RealReg {64fn invalid_sentinel() -> Self {65RealReg::from(PReg::invalid())66}67}68impl InvalidSentinel for Writable<Reg> {69fn invalid_sentinel() -> Self {70Writable::from_reg(Reg::invalid_sentinel())71}72}7374impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {75/// Create an invalid Value-in-Reg.76pub fn invalid() -> Self {77ValueRegs {78parts: [R::invalid_sentinel(); VALUE_REGS_PARTS],79}80}8182/// Is this Value-to-Reg mapping valid?83pub fn is_valid(self) -> bool {84!self.parts[0].is_invalid_sentinel()85}86/// Is this Value-to-Reg mapping invalid?87pub fn is_invalid(self) -> bool {88self.parts[0].is_invalid_sentinel()89}9091/// Return the single register used for this value, if any.92pub fn only_reg(self) -> Option<R> {93if self.len() == 1 {94Some(self.parts[0])95} else {96None97}98}99100/// Return a slice of the registers storing this value.101pub fn regs(&self) -> &[R] {102&self.parts[0..self.len()]103}104105/// Return a mutable slice of the registers storing this value.106pub fn regs_mut(&mut self) -> &mut [R] {107let len = self.len();108&mut self.parts[0..len]109}110}111112impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {113/// Create a Value-in-R location for a value stored in one register.114pub fn one(reg: R) -> Self {115ValueRegs {116parts: [reg, R::invalid_sentinel()],117}118}119/// Create a Value-in-R location for a value stored in two registers.120pub fn two(r1: R, r2: R) -> Self {121ValueRegs { parts: [r1, r2] }122}123124/// Return the number of registers used.125pub fn len(self) -> usize {126// If rustc/LLVM is smart enough, this might even be vectorized...127(self.parts[0] != R::invalid_sentinel()) as usize128+ (self.parts[1] != R::invalid_sentinel()) as usize129}130131/// Map individual registers via a map function.132pub fn map<NewR, F>(self, f: F) -> ValueRegs<NewR>133where134NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel,135F: Fn(R) -> NewR,136{137ValueRegs {138parts: [f(self.parts[0]), f(self.parts[1])],139}140}141}142143/// Create a writable ValueRegs.144pub(crate) fn writable_value_regs(regs: ValueRegs<Reg>) -> ValueRegs<Writable<Reg>> {145regs.map(|r| Writable::from_reg(r))146}147148/// Strip a writable ValueRegs down to a readonly ValueRegs.149pub(crate) fn non_writable_value_regs(regs: ValueRegs<Writable<Reg>>) -> ValueRegs<Reg> {150regs.map(|r| r.to_reg())151}152153154