| //! Source locations. |
| //! |
| //! Cranelift tracks the original source location of each instruction, and preserves the source |
| //! location when instructions are transformed. |
| |
| use core::fmt; |
| #[cfg(feature = "enable-serde")] |
| use serde_derive::{Deserialize, Serialize}; |
| |
| /// A source location. |
| /// |
| /// This is an opaque 32-bit number attached to each Cranelift IR instruction. Cranelift does not |
| /// interpret source locations in any way, they are simply preserved from the input to the output. |
| /// |
| /// The default source location uses the all-ones bit pattern `!0`. It is used for instructions |
| /// that can't be given a real source location. |
| #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
| #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] |
| pub struct SourceLoc(u32); |
| |
| impl SourceLoc { |
| /// Create a new source location with the given bits. |
| pub fn new(bits: u32) -> Self { |
| Self(bits) |
| } |
| |
| /// Is this the default source location? |
| pub fn is_default(self) -> bool { |
| self == Default::default() |
| } |
| |
| /// Read the bits of this source location. |
| pub fn bits(self) -> u32 { |
| self.0 |
| } |
| } |
| |
| impl Default for SourceLoc { |
| fn default() -> Self { |
| Self(!0) |
| } |
| } |
| |
| impl fmt::Display for SourceLoc { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| if self.is_default() { |
| write!(f, "@-") |
| } else { |
| write!(f, "@{:04x}", self.0) |
| } |
| } |
| } |
| |
| /// Source location relative to another base source location. |
| #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
| #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] |
| pub struct RelSourceLoc(u32); |
| |
| impl RelSourceLoc { |
| /// Create a new relative source location with the given bits. |
| pub fn new(bits: u32) -> Self { |
| Self(bits) |
| } |
| |
| /// Creates a new `RelSourceLoc` based on the given base and offset. |
| pub fn from_base_offset(base: SourceLoc, offset: SourceLoc) -> Self { |
| if base.is_default() || offset.is_default() { |
| Self::default() |
| } else { |
| Self(offset.bits().wrapping_sub(base.bits())) |
| } |
| } |
| |
| /// Expands the relative source location into an absolute one, using the given base. |
| pub fn expand(&self, base: SourceLoc) -> SourceLoc { |
| if self.is_default() || base.is_default() { |
| Default::default() |
| } else { |
| SourceLoc::new(self.0.wrapping_add(base.bits())) |
| } |
| } |
| |
| /// Is this the default relative source location? |
| pub fn is_default(self) -> bool { |
| self == Default::default() |
| } |
| } |
| |
| impl Default for RelSourceLoc { |
| fn default() -> Self { |
| Self(!0) |
| } |
| } |
| |
| impl fmt::Display for RelSourceLoc { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| if self.is_default() { |
| write!(f, "@-") |
| } else { |
| write!(f, "@+{:04x}", self.0) |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use crate::ir::SourceLoc; |
| use alloc::string::ToString; |
| |
| #[test] |
| fn display() { |
| assert_eq!(SourceLoc::default().to_string(), "@-"); |
| assert_eq!(SourceLoc::new(0).to_string(), "@0000"); |
| assert_eq!(SourceLoc::new(16).to_string(), "@0010"); |
| assert_eq!(SourceLoc::new(0xabcdef).to_string(), "@abcdef"); |
| } |
| } |