use std::{
fmt::Display,
ops::{Add, Sub},
};
use zhc_utils::{Dumpable, SafeAs, StoreIndex};
macro_rules! impl_index {
($name: ident, $raw: ident, $raw_type: ident, $doc: expr) => {
pub type $raw = $raw_type;
#[doc = $doc]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $name(pub $raw);
impl Add<$raw> for $name {
type Output = $name;
fn add(self, rhs: $raw) -> Self::Output {
$name(self.0 + rhs)
}
}
impl Sub<$raw> for $name {
type Output = $name;
fn sub(self, rhs: $raw) -> Self::Output {
$name(self.0 - rhs)
}
}
impl $name {
pub fn range(start: $raw, end: $raw) -> impl DoubleEndedIterator<Item = $name> {
(start..end).map(|a| $name(a))
}
}
impl StoreIndex for $name {
type Raw = $raw;
fn as_usize(&self) -> usize {
self.0.sas()
}
fn as_raw(&self) -> $raw {
self.0
}
fn raw_from_usize(val: usize) -> $raw {
val.sas()
}
fn from_usize(val: usize) -> $name {
$name(val.sas())
}
}
impl From<$name> for usize {
fn from(value: $name) -> Self {
<$name as StoreIndex>::as_usize(&value)
}
}
};
}
impl_index!(
OpId,
OpIdRaw,
u32,
"Identifier for operations within an IR."
);
impl_index!(ValId, ValIdRaw, u32, "Identifier for values within an IR.");
impl_index!(
ValueNumber,
ValueNumberRaw,
u32,
"Identifier used in value numbering for optimization passes."
);
impl Display for ValId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
write!(f, "%_{}", self.0)
} else {
write!(f, "%{}", self.0)
}
}
}
impl Dumpable for ValId {
fn dump_to_string(&self) -> String {
self.to_string()
}
}
impl Display for OpId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(width) = f.width() {
write!(f, "@{:0width$}", self.0, width = width)
} else {
write!(f, "@{}", self.0)
}
}
}
impl Dumpable for OpId {
fn dump_to_string(&self) -> String {
self.to_string()
}
}