1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
//! 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::{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)]
#[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.
///
/// # Panics
///
/// Panics if the offset is smaller than the base.
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");
}
}